上次学习了单向链表的相关内容。此次主要研究一下双向链表。node
在单向链表中,每次找到一个结点,都要经历一个循环。若是在找到当前结点后,想要找到前面的结点,还要从新进行一次循环。markdown
而双向链表中,是在单向链表的基础上,增长了一个指向前一个结点的指针。这样,经过空间换时间的方式,在不少操做中,会大幅的提升操做链表的效率。数据结构
下面咱们开始具体聊聊双向链表。post
上篇文章单向链表,没有介绍相关链表的概念。我的感受,单向的比较简单。但在双向链表上,前面已经提到了,新增了指向钱一个结点的指针,操做起来要比单向链表复杂了一些,尤为在双向循环链表中,若是头脑中没有一个相对来讲的图形概念,很容易把本身绕晕。我在这篇文章把相关的概念补充补充。学习
单向量表结点包含两个域:数据域和指针域spa
与单向链表结点相比,多了一个指针域。也就是说,它有一个数据域和两个指针域。下面图片中data是数据域,指针域next和prior,分别指向后面结点的地址前面结点的地址。 指针
单向链表是按照前一个结点指向后一个结点的方式,依次将结点链接起来的一种表现形式。code
如此细分的缘由:当进行链表操做时(插入、删除、改、查),不一样类型的结点处理方式不一样。好比插入一个结点到单向量表中,插入的结点用node表示:orm
文字有点苍白,仍是图来的直观点图片
和单向链表相比,双向链表的结点中多了一个指向前结点的指针域。直接看图,比较直观一些
双向循环链表经过前面的概念,看看图也是很好理解的。
在首元结点以前增长一个头结点,用来指向链表起始点。
p.s. 不信?你能够本身写写不带头结点的链表增删改查,你就知道有多恶心了!!!
单向链表相关代码实现,请参考上篇文章20200401-数据结构-单向链表
我多说了,开始上代码。如下代码的主要目录流程
准备代码
#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int ElemType; typedef int Status; typedef struct Node * LinkList; typedef struct Node{ ElemType data; LinkList prior; LinkList next; }Node; 复制代码
初始化
Status createList(LinkList *list, int length) { *list = (LinkList)malloc(sizeof(Node)); if (!*list) { return ERROR; } LinkList p = *list; p->data = -1; p->prior = NULL; p->next = NULL; for (int i = 1; i <= length; i++) { LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = i; node->prior = NULL; node->next = NULL; p->next = node; node->prior = p; p = p->next; } return OK; } 复制代码
打印链表
Status displayList(LinkList list) { if (list == NULL) { printf("空链表不打印"); return ERROR; } LinkList p = list->next; while (p) { printf("%5d", p->data); p = p->next; } printf("\n"); return OK; } 复制代码
增长元素
Status insertNode(LinkList *list, int pos, ElemType value) { if (pos < 1) { return ERROR; } if ((*list)->next == NULL) { return ERROR; } LinkList p = (*list); int i; for (i = 1; i < pos && p; i++) { p = p->next; } if (p == NULL) { printf("插入位置大于链表长度\n"); return ERROR; } LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = value; node->prior = NULL; node->next = NULL; if (p->next == NULL) { p->next = node; node->prior = p; } else { p->next->prior = node; node->next = p->next; node->prior = p; p->next = node; } return OK; } 复制代码
删除元素
//根据指定位置 删除结点 Status listDelPos(LinkList *list, int pos, ElemType *delData) { if (pos < 1) { return ERROR; } LinkList p = *list; if (p->next == NULL) { return ERROR; } int i; for (i = 1; i <= pos && p; i++) { p = p->next; } if (!p) { return ERROR; } *delData = p->data; if (p->next == NULL) { p->prior->next = NULL; } else { p->prior->next = p->next; p->next->prior = p->prior; } free(p); return OK; } //根据value 删除结点 Status listDelVal(LinkList *list, ElemType value) { LinkList p = *list; int ret = ERROR; while (p->next) { p = p->next; if (value == p->data) { p->prior->next = p->next; if (p->next) { p->next->prior = p->prior; } ret = OK; break; } } return ret; } 复制代码
修改元素
Status updateListIndexNode(LinkList *list, int index, ElemType elem) { LinkList p = (*list)->next; for (int i = 1; i < index && p; i++) { p = p->next; } if (p) { p->data = elem; } else { return ERROR; } return OK; } 复制代码
查找元素
int listSelectElem(LinkList list, ElemType elem) { int index = 1; LinkList p = list->next; while (p) { if (p->data == elem) { return index; } p = p->next; index++; } return -1; } 复制代码
初始化
Status createList(LinkList *list) { *list = (LinkList)malloc(sizeof(Node)); if (!*list) { return ERROR; } LinkList p = *list; p->data = -1; p->prior = NULL; p->next = NULL; for (int i = 1; i <= 5; i++) { LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = i; node->next = *list; node->prior = p; p->next = node; (*list)->prior = node; p = p->next; } return OK; } 复制代码
打印链表
Status displayList(LinkList list) { if (list == NULL) { return ERROR; } LinkList p = list->next; while (p != list) { printf("%5d", p->data); p = p->next; } printf("\n"); return OK; } 复制代码
增长元素
Status insertValue(LinkList *list, int pos, ElemType value) { LinkList p = *list; if (p == NULL) { return ERROR; } int i = 1; while (i < pos && p->next != *list) { p = p->next; i++; } if (i > pos) { return ERROR; } LinkList node = (LinkList)malloc(sizeof(Node)); if (node == NULL) { return ERROR; } node->data = value; node->prior = p; node->next = p->next; node->next->prior = node; p->next = node; return OK; } 复制代码
删除元素
Status delValue(LinkList *list, int pos, ElemType *e) { if (*list == NULL) { return ERROR; } LinkList p = (*list)->next; int i = 1; while (i < pos && p->next != *list) { p = p->next; i++; } if (i != pos && p->next == *list) { printf("要删除的位置大于链表的长度"); return ERROR; } *e = p->data; p->next->prior = p->prior; p->prior->next = p->next; free(p); if ((*list)->next == NULL) { free(*list); *list = NULL; return OK; } return OK; } 复制代码
以上代码能够有些边界值考虑不周到的地方,你们根据具体需求进行修改吧。链表的操做不要去背代码,而要去理解。想不通的地方,能够在纸上多画画。本人博客新手,有很差的地方,还请你们指出,我会学着去修改。
谢谢!!!
仍是用那句话收尾:沿途的风景要比目的地更弯的否!!!