当前位置:   article > 正文

C语言数据结构之双向链表_c语言 双向链表

c语言 双向链表

前言

        前面介绍了单链表,由于单链表遍历查找是单向性的,故引出了双向链表的概念,也叫双链表,既可以向前查找,也可以向后遍历。

C语言数据结构之单链表

C语言数据结构之双向链表

c语言数据结构之栈

c语言数据结构之队列
​​​​​​​
C语言数据结构之树

1   双链表

1.1  基本结构

在单链表的基础上增加一个前驱指针,每个数据结点中都有两个指针,分别指向直接后继和直接前驱。初始化一个头节点,前驱指针和后驱指针均指向NULL,头节点的数据域是有数据的,这点跟单链表不同。

pre表示前驱指针,指向当前结点的前一个结点,如果当前结点是头结点,则pre指针为空;

next表示后继指针,指向当前结点的下一个结点,如果当前结点是尾结点,则next指针为空。

  1. typedef struct _NODE {
  2. int data;
  3. struct _NODE *next; //后继指针
  4. struct _NODE *pre; //前驱指针
  5. }Node,*Nodelist;

1.1  创建双链表

调用malloc函数申请内存的时候返回值是指向申请的地址,如果申请失败返回NULL,这里我们最好要养成习惯判断是否内存申请成功;exit函数的作用是退出当前程序的进程;头节点的两个指针都指向NULL,并给头节点输入数据;当输入文件结束符(window下输入ctrl+z、linux下输入ctrl+d)的时候就完成链表的创建。

  1. Nodelist double_link_create()
  2. {
  3. int Data = 0;
  4. Node *p = NULL;
  5. Node *head = (Nodelist)malloc(sizeof(Node));
  6. if(head == NULL){
  7. printf("head malloc fail.\n");
  8. exit(-1);
  9. }
  10. head->pre = NULL;
  11. head->next = NULL;
  12. printf("window下输入ctrl+z完成创建;linux下输入ctrl+d完成创建\n");
  13. printf("please input data:");
  14. scanf("%d",&Data);
  15. head->data = Data;
  16. p = head;
  17. while(scanf("%d",&Data) != EOF){
  18. Node *q = (Nodelist)malloc(sizeof(Node));
  19. if(q == NULL){
  20. printf("malloc fail.\n");
  21. exit(-1);
  22. }
  23. q->data = Data;
  24. q->pre = p;
  25. q->next = NULL;
  26. p->next = q;
  27. p = q;
  28. }
  29. return head;
  30. }

1.2  链表中插入新节点

双向链表的插入操作,首先需要开辟一个新的节点内存空间,然后将它的pre指针指向所需插入位置的前一个结点,同时,它所需插入的前一个结点的next指针修改指向为该新的结点,同理,该新的结点的next指针将会指向一个原本的下一个结点,而修改下一个结点的pre指针为指向新结点自身。

还需要对插入位置进行考虑:①插入到头节点位置处理;②插入到链表中间处理;③插入到表尾处理;④插入位置超过链表本身长度处理。

  1. Nodelist double_link_insert(Nodelist h, int addr, int data)
  2. {
  3. Node *p = h;
  4. Node *add_node = (Nodelist)malloc(sizeof(Node));
  5. if(add_node == NULL){
  6. printf("malloc fail.\n");
  7. exit(-1);
  8. }
  9. add_node->data = data;
  10. if(addr == 1){ //插入到头节点要特殊考虑
  11. add_node->pre = NULL;
  12. add_node->next = p;
  13. p->pre = add_node;
  14. h = add_node; //头节点指向新节点
  15. return h;
  16. }
  17. else{
  18. for(int i = 1; i < addr; i++){
  19. if(p->next != NULL){
  20. p = p->next;
  21. }
  22. else{ //addr错误则将新节点链接在表尾
  23. printf("addr is too large\n");
  24. add_node->pre = p;
  25. add_node->next = NULL;
  26. p->next = add_node;
  27. return h;
  28. }
  29. }
  30. add_node->pre = p->pre;
  31. add_node->next = p;
  32. p->pre = add_node;
  33. }
  34. return h;
  35. }

1.3  链表删除节点

首先,指定需要删除的结点位置,选中这个结点的前一个结点,将前一个结点的next指针指向自己的下一个结点,同时,选中该节点的下一个结点,将下一个结点的pre指针修改指向为自己的上一个结点,最后,释放删除结点的内存空间。

逻辑注意事项:①假设指定删除位置超过链表本身长度如何处理;②删除头节点处理;③删除为节点处理;④删除中间节点处理。

  1. Nodelist double_link_delete(Nodelist h, int addr)
  2. {
  3. Node *p = h;
  4. for(int i = 1; i < addr; i++){
  5. if(p->next != NULL){
  6. p = p->next;
  7. }
  8. else{
  9. printf("addr error,function exit.\n");
  10. return h;
  11. }
  12. }
  13. if(addr == 1){ //删除头节点
  14. p->next->pre = NULL;
  15. h = p->next;
  16. free(p);
  17. }
  18. else{
  19. if(p->next == NULL){ //删除尾节点
  20. p->pre->next = NULL;
  21. free(p);
  22. }
  23. else{
  24. p->pre->next = p->next;
  25. p->next->pre = p->pre;
  26. free(p);
  27. }
  28. }
  29. return h;
  30. }

2  示例程序

双链表主要懂如何插入、删除操作,其它的修改、查询、打印等都跟单链表差不多,逻辑点比较简单,重点是学会对指针的使用。

  1. /****************************************
  2. Fuction:C语言实现双向链表
  3. Time:9/21/2022
  4. Author:Qurry
  5. ****************************************/
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. typedef struct _NODE {
  9. int data;
  10. struct _NODE *next; //后继指针
  11. struct _NODE *pre; //前驱指针
  12. }Node,*Nodelist;
  13. /********** 创建双链表 ************/
  14. Nodelist double_link_create()
  15. {
  16. int Data = 0;
  17. Node *p = NULL;
  18. Node *head = (Nodelist)malloc(sizeof(Node));
  19. if(head == NULL){
  20. printf("head malloc fail.\n");
  21. exit(-1);
  22. }
  23. head->pre = NULL;
  24. head->next = NULL;
  25. printf("window下输入ctrl+z完成创建;linux下输入ctrl+d完成创建\n");
  26. printf("please input data:");
  27. scanf("%d",&Data);
  28. head->data = Data;
  29. p = head;
  30. while(scanf("%d",&Data) != EOF){
  31. Node *q = (Nodelist)malloc(sizeof(Node));
  32. if(q == NULL){
  33. printf("malloc fail.\n");
  34. exit(-1);
  35. }
  36. q->data = Data;
  37. q->pre = p;
  38. q->next = NULL;
  39. p->next = q;
  40. p = q;
  41. }
  42. return head;
  43. }
  44. /********* 链表增加节点 ***********
  45. * addr:增加节点的位置
  46. * data:增加节点的数据
  47. * ********************************/
  48. Nodelist double_link_insert(Nodelist h, int addr, int data)
  49. {
  50. Node *p = h;
  51. Node *add_node = (Nodelist)malloc(sizeof(Node));
  52. if(add_node == NULL){
  53. printf("malloc fail.\n");
  54. exit(-1);
  55. }
  56. add_node->data = data;
  57. if(addr == 1){ //插入到头节点要特殊考虑
  58. add_node->pre = NULL;
  59. add_node->next = p;
  60. p->pre = add_node;
  61. h = add_node; //头节点指向新节点
  62. return h;
  63. }
  64. else{
  65. for(int i = 1; i < addr; i++){
  66. if(p->next != NULL){
  67. p = p->next;
  68. }
  69. else{ //addr错误则将新节点链接在表尾
  70. printf("addr is too large\n");
  71. add_node->pre = p;
  72. add_node->next = NULL;
  73. p->next = add_node;
  74. return h;
  75. }
  76. }
  77. add_node->pre = p->pre;
  78. add_node->next = p;
  79. p->pre = add_node;
  80. }
  81. return h;
  82. }
  83. /*********** 链表删除节点 *************
  84. * addr:删除节点的位置
  85. * **************************************/
  86. Nodelist double_link_delete(Nodelist h, int addr)
  87. {
  88. Node *p = h;
  89. for(int i = 1; i < addr; i++){
  90. if(p->next != NULL){
  91. p = p->next;
  92. }
  93. else{
  94. printf("addr error,function exit.\n");
  95. return h;
  96. }
  97. }
  98. if(addr == 1){ //删除头节点
  99. p->next->pre = NULL;
  100. h = p->next;
  101. free(p);
  102. }
  103. else{
  104. if(p->next == NULL){ //删除尾节点
  105. p->pre->next = NULL;
  106. free(p);
  107. }
  108. else{
  109. p->pre->next = p->next;
  110. p->next->pre = p->pre;
  111. free(p);
  112. }
  113. }
  114. return h;
  115. }
  116. /********** 链表修改数据 **********
  117. * old_data:要修改的数据
  118. * new_data:修改后的数据
  119. * ****************************************/
  120. void double_link_modify(Nodelist h, int old_data, int new_data)
  121. {
  122. Node *p = h;
  123. while(p->data != old_data){
  124. if(p->next != NULL){
  125. p = p->next;
  126. }
  127. else{
  128. printf("old_data error!\n");
  129. return;
  130. }
  131. }
  132. p->data = new_data;
  133. }
  134. /******** 链表查找数据 *********
  135. * addr:查找数据的位置
  136. * *********************************/
  137. void double_link_find(Nodelist h, int addr)
  138. {
  139. Node *p = h;
  140. for(int i = 1; i < addr; i++){
  141. if(p->next != NULL){
  142. p = p->next;
  143. }
  144. else{
  145. printf("addr error,function exit.\n");
  146. return;
  147. }
  148. }
  149. printf("Data:%d\n",p->data);
  150. }
  151. /********** 链表数据打印 **********/
  152. void double_link_print(Nodelist h)
  153. {
  154. Node *p = h;
  155. int inode = 1;
  156. while(1){
  157. printf("Node[%d]:%d\n",inode++,p->data);
  158. if(p->next == NULL){
  159. return;
  160. }
  161. else{
  162. p = p->next;
  163. }
  164. }
  165. }
  166. /*********** 选择菜单 **************/
  167. int menu_select()
  168. {
  169. int num;
  170. printf("1:插入节点 2:修改节点 3:删除节点 4:打印节点数据 5:查找节点数据 0:退出\n");
  171. printf("Please input num : ");
  172. scanf("%d",&num);
  173. return num;
  174. }
  175. /************ 退出释放内存 ************/
  176. void free_node(Nodelist H)
  177. {
  178. Node *P = H->next;
  179. while(1){
  180. free(P);
  181. P = P->next;
  182. if(P->next == NULL){
  183. free(P);
  184. break;
  185. }
  186. }
  187. }
  188. void main()
  189. {
  190. Node *head = NULL;
  191. int mode,addr,data1,data2;
  192. head = double_link_create();
  193. while(1){
  194. mode = menu_select();
  195. switch (mode)
  196. {
  197. case 0:
  198. printf("Bye bye!\n");
  199. free_node(head);
  200. exit(0);
  201. case 1:
  202. printf("please input addr & data:");
  203. scanf("%d %d",&addr,&data1);
  204. head = double_link_insert(head,addr,data1);
  205. break;
  206. case 2:
  207. printf("please input old data & new data:");
  208. scanf("%d %d",&data1,&data2);
  209. double_link_modify(head,data1,data2);
  210. break;
  211. case 3:
  212. printf("please input addr:");
  213. scanf("%d",&addr);
  214. head = double_link_delete(head,addr);
  215. break;
  216. case 4:
  217. double_link_print(head);
  218. break;
  219. case 5:
  220. printf("please input addr:");
  221. scanf("%d",&addr);
  222. double_link_find(head,addr);
  223. break;
  224. default:
  225. printf("input num error!\n");
  226. break;
  227. }
  228. }
  229. }

linux下测试结果

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号