数据结构:双链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点

双链表和单链表的区别
- 单链表对于一个节点,有储存数据的data。和next后驱节点(指针)。也就是这个单链表想要一些遍历的操作都得通过前节点—>后节点。
- 双链表对于一个节点,有些和单链表一样有存储数据的data,指向后方的next(指针)。它拥有单链表的所有操作和内容。但是他还有一个前驱节点front(指针)。
- 单链表一般都有一个头结点,双向链表可以没有头结点。
本次创建的为一个没有头结点的双链表
双链表的创建
1 2 3 4 5 6 7 8 9
| typedef struct dlinklist { int number; struct dlinklist *front; struct dlinklist *next; }DLlinkList;
|
正因为拥有两个指针,所以双链表可以正向遍历也可以反向遍历。
双链表的初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| DLlinkList* init_list(int n) { int i; DLlinkList *head,*node,*end;
if(n <= 0) { return NULL; }
node = (DLlinkList*)malloc(sizeof(DLlinkList)); scanf("%d",&node->number); head = node; end = node; for (i = 1; i < n; i++) { node = (DLlinkList*)malloc(sizeof(DLlinkList)); scanf("%d",&node->number); end->next = node; node->front = end; end = node; } head->front = NULL; end->next = NULL; return head; }
|
相比单链表,他们的操作基本一样,双链表多了前驱指针的操作。
增加节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| DLlinkList * add_node(DLlinkList *list, int n) { DLlinkList *temp = list; DLlinkList *in; int i = 0; if (temp == NULL) { printf("list is empty!\n"); return; }
while (i < (n-1) && temp != NULL) { i++; temp = temp->next; }
if (temp != NULL) { in = (DLlinkList*)malloc(sizeof(DLlinkList)); scanf("%d",&in->number); if (temp->front == NULL) { in->next = list; in->front = NULL; list = in; } else if (temp->next == NULL) { temp->next = in; in->front = temp; in->next = NULL; } else { in->next = temp->next; in->front = temp; temp->next = in; } } else { printf("The %d node is empty,list has %d node\n",n,i); } }
|
因为没有头结点,第一个节点可能会改变(头插时),所以返回值是一个节点的指针。
此函数包括了头插,尾插,和中间插入的逻辑。
删除节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| DLlinkList * del_node(DLlinkList *list, int n) { DLlinkList *temp = list; DLlinkList *out; int i = 0; if (temp == NULL) { printf("list is empty!\n"); return; } if (n <= 0) { printf("n is error!\n"); return; }
while (i < (n - 1) && temp != NULL) { i++; temp = temp->next; }
if (temp != NULL) { if (temp->front == NULL) { out = list; list = list->next; list->front = NULL; } else if (temp->next == NULL) { out = temp; out->front->next = NULL; } else { out = temp; out->front->next = out->next; out->next->front = out->front; out = NULL; }
free(out); } else { printf("The %d node is empty,list has %d node\n",n,i); } return list; }
|
删除节点和增加节点一样,包含了三个逻辑:删除头,删除尾,删除中间
修改节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| void modify_num(LINKLIST *list,int n) { LINKLIST *temp = list; int i = 0; if (temp == NULL) { printf("list is empty!"); return; }
while (i < n && temp != NULL) { i++; temp = temp->next; }
if (temp != NULL) { scanf("%d",&temp->number); } else { printf("the %d node is empty!\n",n); }
|
修改节点比较简单,遍历修改number就可以
输出双链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| void printf_list(DLlinkList *list) { DLlinkList *temp = list; if (temp == NULL) { printf("list is empty!"); return; }
if (temp->front == NULL && temp->next == NULL) { printf("list number:%d\n",temp->number); return; } else if (temp->front == NULL) { while (temp != NULL) { printf("list number:%d\n",temp->number); temp = temp->next; } } else { while (temp != NULL) { printf("list number:%d\n",temp->number); temp = temp->front; } }
return; }
|
输出操作包含了从头部输出和从尾部输出两个逻辑