当前位置:   article > 正文

数据结构(学习)2024.8.9(双向链表)

数据结构(学习)2024.8.9(双向链表)

今天学习的是线性表里面的最后一部分双向链表

栈和队列的相关知识可以查看http://t.csdnimg.cn/R1ls3

链表的相关知识可以查看http://t.csdnimg.cn/NX464

顺序表的相关知识可以查看http://t.csdnimg.cn/5IMAZ

目录

双向链表

结构体

操作函数

1.创建一个空的双向链表

2.向双向链表的指定位置插入数据

3.遍历双向链表

4.删除双向链表指定位置的数据

5.删除双向链表中的指定数据

双向链表的相关操作案例

双向链表

1.逻辑结构:线性结构
2.存储结构:链式存储
3.操作:增、删、改、查

结构体

typedef struct node_t
{
    datatype data;          // 数据域
    struct node_t *next;  // 指向下一个节点的指针 next 下一个
    struct node_t *prior; // 指向前一个节点的指针 prior 前一个
} link_node_t, *link_list_t;

// 将双向链表的头指针和尾指针封装到一个结构体里,有点像学的链式队列

typedef struct doublelinklist
{
    link_list_t head; // 指向双向链表的头指针
    link_list_t tail; // 指向双向链表的尾指针
    int len;
} double_node_t, *double_list_t;

操作函数

1.创建一个空的双向链表

  1. double_list_t createEmptyDoubleLinkList()
  2. {
  3. double_list_t p = (double_list_t)malloc(sizeof(double_node_t));
  4. if (p == NULL)
  5. {
  6. perror("createEmptyDoubleLinkList函数创建结构体出错\n");
  7. return NULL;
  8. }
  9. p->len = 0;
  10. p->head = p->tail = (link_list_t)malloc(sizeof(link_node_t));
  11. if (p->head == NULL)
  12. {
  13. perror("createEmptyDoubleLinkList创建链表节点出错\n");
  14. return NULL;
  15. }
  16. p->head->next = NULL;
  17. p->head->prior = NULL;
  18. return p;
  19. }

2.向双向链表的指定位置插入数据

  1. int insertIntoDoubleLinkList(double_list_t p, int post, datatype data)
  2. {
  3. // 1.容错判断
  4. if (post < 0 || post > p->len)
  5. {
  6. perror("insertIntoDoubleLinkList函数出错\n");
  7. return -1;
  8. }
  9. // 2.开辟一个新节点空间存放数据
  10. link_list_t pnew = (link_list_t)malloc(sizeof(link_node_t));
  11. if (pnew == NULL)
  12. {
  13. perror("insertIntoDoubleLinkList函数创建新节点出错\n");
  14. return -1;
  15. }
  16. pnew->data = data;
  17. pnew->next = NULL;
  18. pnew->prior = NULL;
  19. link_list_t temp = NULL;
  20. // 3.将结点插入链表
  21. // (1).先对插入的位置进行判断
  22. if (post == p->len) // 尾插
  23. {
  24. p->tail->next = pnew;
  25. pnew->prior = p->tail;
  26. p->tail = pnew; // 移动尾指针
  27. }
  28. else // 中间插
  29. {
  30. // (1)将temp移动到被插入的位置
  31. if (post < p->len / 2) // 前半段
  32. {
  33. temp = p->head;
  34. for (int i = 0; i <= post; i++)
  35. {
  36. temp = temp->next;
  37. }
  38. }
  39. else // 后半段
  40. {
  41. temp = p->tail;
  42. for (int i = 0; i < p->len - 1 - post; i++)
  43. {
  44. temp = temp->prior;
  45. }
  46. }
  47. // (2)进行插入操作(先连前面,再连后面)
  48. temp->prior->next = pnew;
  49. pnew->prior = temp->prior;
  50. pnew->next = temp;
  51. temp->prior = pnew;
  52. }
  53. // 长度+1
  54. p->len++;
  55. return 0;
  56. }

3.遍历双向链表

  1. void showDoubleLinkList(double_list_t p)
  2. {
  3. link_list_t temp = NULL;
  4. printf("正向遍历:\n");
  5. temp = p->head;
  6. while (temp->next != NULL)
  7. {
  8. temp = temp->next;
  9. printf("%d ", temp->data);
  10. }
  11. printf("\n");
  12. printf("反向遍历:\n");
  13. temp = p->tail;
  14. while (temp != p->head)
  15. {
  16. printf("%d ", temp->data);
  17. temp = temp->prior;
  18. }
  19. printf("\n");
  20. }

4.删除双向链表指定位置的数据

  1. int deletePostDoubleLinkList(double_list_t p, int post)
  2. {
  3. // 1.容错判断
  4. if (post < 0 || post >= p->len || isEmptyDoubleLinkList(p))
  5. {
  6. perror("deletePostDoubleLinkList函数出错\n");
  7. return -1;
  8. }
  9. // 2.对删除的位置进行判断
  10. link_list_t temp = NULL;
  11. if (post == p->len - 1) // 尾删
  12. {
  13. // 向前移动尾指针
  14. p->tail = p->tail->prior;
  15. // 释放被删除的节点
  16. free(p->tail->next);
  17. p->tail->next = NULL;
  18. }
  19. else // 中间删
  20. {
  21. // (1)将temp移动到要删除的位置
  22. if (post < p->len / 2) // 前半段
  23. {
  24. temp = p->head;
  25. for (int i = 0; i <= post; i++)
  26. {
  27. temp = temp->next;
  28. }
  29. }
  30. else // 后半段
  31. {
  32. temp = p->tail;
  33. for (int i = 0; i < p->len - 1 - post; i++)
  34. {
  35. temp = temp->prior;
  36. }
  37. }
  38. // (2)进行删除
  39. temp->prior->next = temp->next;
  40. temp->next->prior = temp->prior;
  41. free(temp);
  42. temp = NULL;
  43. }
  44. // 长度-1
  45. p->len--;
  46. return 0;
  47. }

5.删除双向链表中的指定数据

  1. int deleteDataDoubleLinkList(double_list_t p, datatype data)
  2. {
  3. if (isEmptyDoubleLinkList(p))
  4. {
  5. perror("deleteDataDoubleLinkList函数出错\n");
  6. return -1;
  7. }
  8. link_list_t q = p->head->next;
  9. while (q != NULL)
  10. {
  11. if (q->data == data) // 删除
  12. {
  13. if (q == p->tail) // 尾删
  14. {
  15. p->tail = p->tail->prior;
  16. free(p->tail->next);
  17. p->tail->next = NULL;
  18. q = NULL;
  19. }
  20. else // 中间删
  21. {
  22. q->prior->next = q->next;
  23. q->next->prior = q->prior;
  24. link_list_t pdel = q;
  25. q = q->next;
  26. free(pdel);
  27. pdel = NULL;
  28. }
  29. p->len--;
  30. }
  31. else // 不相等
  32. {
  33. q = q->next;
  34. }
  35. }
  36. return 0;
  37. }

双向链表的相关操作案例

头文件doublelinklist.h:

  1. #ifndef _DOUBLELINKLIST_H_
  2. #define _DOUBLELINKLIST_H_
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. typedef int datatype;
  6. typedef struct node_t
  7. {
  8. datatype data; // 数据域
  9. struct node_t *next; // 指向下一个节点的指针 next 下一个
  10. struct node_t *prior; // 指向前一个节点的指针 prior 前一个
  11. } link_node_t, *link_list_t;
  12. // 将双向链表的头指针和尾指针封装到一个结构体里
  13. // 思想上有点像学的链式队列
  14. typedef struct doublelinklist
  15. {
  16. link_list_t head; // 指向双向链表的头指针
  17. link_list_t tail; // 指向双向链表的尾指针
  18. int len;
  19. } double_node_t, *double_list_t;
  20. // 1.创建一个空的双向链表
  21. double_list_t createEmptyDoubleLinkList();
  22. // 2.向双向链表的指定位置插入数据 post位置, data数据
  23. int insertIntoDoubleLinkList(double_list_t p, int post, datatype data);
  24. // 3.遍历双向链表
  25. void showDoubleLinkList(double_list_t p);
  26. // 4.删除双向链表指定位置的数据
  27. int deletePostDoubleLinkList(double_list_t p, int post);
  28. // 5.判断双向链表是否为空
  29. int isEmptyDoubleLinkList(double_list_t p);
  30. // 6.求双向链表的长度
  31. int lengthDoubleLinkList(double_list_t p);
  32. // 7.查找指定数据出现的位置 data被查找的数据
  33. int searchPostDoubleLinkList(double_list_t p, datatype data);
  34. // 8.修改指定位置的数据,post修改的位置 data被修改的数据
  35. int changeDataDoubleLinkList(double_list_t p, int post, datatype data);
  36. // 9.删除双向链表中的指定数据 data代表删除所有出现的data数据
  37. int deleteDataDoubleLinkList(double_list_t p, datatype data);
  38. #endif

双向链表函数doublelinklist.c:

  1. #include "doublelinklist.h"
  2. // 1.创建一个空的双向链表
  3. double_list_t createEmptyDoubleLinkList()
  4. {
  5. double_list_t p = (double_list_t)malloc(sizeof(double_node_t));
  6. if (p == NULL)
  7. {
  8. perror("createEmptyDoubleLinkList函数创建结构体出错\n");
  9. return NULL;
  10. }
  11. p->len = 0;
  12. p->head = p->tail = (link_list_t)malloc(sizeof(link_node_t));
  13. if (p->head == NULL)
  14. {
  15. perror("createEmptyDoubleLinkList创建链表节点出错\n");
  16. return NULL;
  17. }
  18. p->head->next = NULL;
  19. p->head->prior = NULL;
  20. return p;
  21. }
  22. // 2.向双向链表的指定位置插入数据 post位置, data数据
  23. int insertIntoDoubleLinkList(double_list_t p, int post, datatype data)
  24. {
  25. // 1.容错判断
  26. if (post < 0 || post > p->len)
  27. {
  28. perror("insertIntoDoubleLinkList函数出错\n");
  29. return -1;
  30. }
  31. // 2.开辟一个新节点空间存放数据
  32. link_list_t pnew = (link_list_t)malloc(sizeof(link_node_t));
  33. if (pnew == NULL)
  34. {
  35. perror("insertIntoDoubleLinkList函数创建新节点出错\n");
  36. return -1;
  37. }
  38. pnew->data = data;
  39. pnew->next = NULL;
  40. pnew->prior = NULL;
  41. link_list_t temp = NULL;
  42. // 3.将结点插入链表
  43. // (1).先对插入的位置进行判断
  44. if (post == p->len) // 尾插
  45. {
  46. p->tail->next = pnew;
  47. pnew->prior = p->tail;
  48. p->tail = pnew; // 移动尾指针
  49. }
  50. else // 中间插
  51. {
  52. // (1)将temp移动到被插入的位置
  53. if (post < p->len / 2) // 前半段
  54. {
  55. temp = p->head;
  56. for (int i = 0; i <= post; i++)
  57. {
  58. temp = temp->next;
  59. }
  60. }
  61. else // 后半段
  62. {
  63. temp = p->tail;
  64. for (int i = 0; i < p->len - 1 - post; i++)
  65. {
  66. temp = temp->prior;
  67. }
  68. }
  69. // (2)进行插入操作(先连前面,再连后面)
  70. temp->prior->next = pnew;
  71. pnew->prior = temp->prior;
  72. pnew->next = temp;
  73. temp->prior = pnew;
  74. }
  75. // 长度+1
  76. p->len++;
  77. return 0;
  78. }
  79. // 3.遍历双向链表
  80. void showDoubleLinkList(double_list_t p)
  81. {
  82. link_list_t temp = NULL;
  83. printf("正向遍历:\n");
  84. temp = p->head;
  85. while (temp->next != NULL)
  86. {
  87. temp = temp->next;
  88. printf("%d ", temp->data);
  89. }
  90. printf("\n");
  91. printf("反向遍历:\n");
  92. temp = p->tail;
  93. while (temp != p->head)
  94. {
  95. printf("%d ", temp->data);
  96. temp = temp->prior;
  97. }
  98. printf("\n");
  99. }
  100. // 4.删除双向链表指定位置的数据
  101. int deletePostDoubleLinkList(double_list_t p, int post)
  102. {
  103. // 1.容错判断
  104. if (post < 0 || post >= p->len || isEmptyDoubleLinkList(p))
  105. {
  106. perror("deletePostDoubleLinkList函数出错\n");
  107. return -1;
  108. }
  109. // 2.对删除的位置进行判断
  110. link_list_t temp = NULL;
  111. if (post == p->len - 1) // 尾删
  112. {
  113. // 向前移动尾指针
  114. p->tail = p->tail->prior;
  115. // 释放被删除的节点
  116. free(p->tail->next);
  117. p->tail->next = NULL;
  118. }
  119. else // 中间删
  120. {
  121. // (1)将temp移动到要删除的位置
  122. if (post < p->len / 2) // 前半段
  123. {
  124. temp = p->head;
  125. for (int i = 0; i <= post; i++)
  126. {
  127. temp = temp->next;
  128. }
  129. }
  130. else // 后半段
  131. {
  132. temp = p->tail;
  133. for (int i = 0; i < p->len - 1 - post; i++)
  134. {
  135. temp = temp->prior;
  136. }
  137. }
  138. // (2)进行插入删除
  139. temp->prior->next = temp->next;
  140. temp->next->prior = temp->prior;
  141. free(temp);
  142. temp = NULL;
  143. }
  144. // 长度-1
  145. p->len--;
  146. return 0;
  147. }
  148. // 5.判断双向链表是否为空
  149. int isEmptyDoubleLinkList(double_list_t p)
  150. {
  151. return p->len == 0;
  152. }
  153. // 6.求双向链表的长度
  154. int lengthDoubleLinkList(double_list_t p)
  155. {
  156. return p->len;
  157. }
  158. // 7.查找指定数据出现的位置 data被查找的数据
  159. int searchPostDoubleLinkList(double_list_t p, datatype data)
  160. {
  161. link_list_t q = p->head;
  162. int post = 0;
  163. while (q->next != NULL)
  164. {
  165. q = q->next;
  166. if (q->data == data)
  167. {
  168. return post;
  169. }
  170. post++;
  171. }
  172. return -1;
  173. }
  174. // 8.修改指定位置的数据,post修改的位置 data被修改的数据
  175. int changeDataDoubleLinkList(double_list_t p, int post, datatype data)
  176. {
  177. // 1.容错判断
  178. if (post < 0 || post >= p->len)
  179. {
  180. perror("changeDataDoubleLinkList函数出错\n");
  181. return -1;
  182. }
  183. // 2.移动指针
  184. link_list_t temp = NULL;
  185. if (post < p->len / 2) // 前半段
  186. {
  187. temp = p->head;
  188. for (int i = 0; i <= post; i++)
  189. {
  190. temp = temp->next;
  191. }
  192. }
  193. else // 后半段
  194. {
  195. temp = p->tail;
  196. for (int i = 0; i < p->len - 1 - post; i++)
  197. {
  198. temp = temp->prior;
  199. }
  200. }
  201. // 3.修改数据
  202. temp->data = data;
  203. return 0;
  204. }
  205. // 9.删除双向链表中的指定数据 data代表删除所有出现的data数据
  206. int deleteDataDoubleLinkList(double_list_t p, datatype data)
  207. {
  208. if (isEmptyDoubleLinkList(p))
  209. {
  210. perror("deleteDataDoubleLinkList函数出错\n");
  211. return -1;
  212. }
  213. link_list_t q = p->head->next;
  214. while (q != NULL)
  215. {
  216. if (q->data == data) // 删除
  217. {
  218. if (q == p->tail) // 尾删
  219. {
  220. p->tail = p->tail->prior;
  221. free(p->tail->next);
  222. p->tail->next = NULL;
  223. q = NULL;
  224. }
  225. else // 中间删
  226. {
  227. q->prior->next = q->next;
  228. q->next->prior = q->prior;
  229. link_list_t pdel = q;
  230. q = q->next;
  231. free(pdel);
  232. pdel = NULL;
  233. }
  234. p->len--;
  235. }
  236. else // 不相等
  237. {
  238. q = q->next;
  239. }
  240. }
  241. return 0;
  242. }

主函数main.c:

  1. #include "doublelinklist.h"
  2. int main(int argc, char const *argv[])
  3. {
  4. int post;
  5. int data;
  6. double_list_t p = createEmptyDoubleLinkList();
  7. insertIntoDoubleLinkList(p, 0, 1);
  8. insertIntoDoubleLinkList(p, 1, 2);
  9. insertIntoDoubleLinkList(p, 2, 3);
  10. insertIntoDoubleLinkList(p, 3, 4);
  11. printf("双向链表为:\n");
  12. showDoubleLinkList(p);
  13. printf("双向链表的长度为:\n");
  14. printf("%d\n", lengthDoubleLinkList(p));
  15. printf("请输入你要插入的数据的位置和数据:\n");
  16. scanf(" %d %d", &post, &data);
  17. insertIntoDoubleLinkList(p, post, data);
  18. printf("插入数据以后的双向链表为:\n");
  19. showDoubleLinkList(p);
  20. printf("请输入你要删除的数据的位置:\n");
  21. scanf(" %d", &post);
  22. deletePostDoubleLinkList(p, post);
  23. printf("删除以后的双向链表为:\n");
  24. showDoubleLinkList(p);
  25. printf("双向链表的长度为:\n");
  26. printf("%d\n", lengthDoubleLinkList(p));
  27. printf("请输入你要查询的数据:\n");
  28. scanf(" %d", &data);
  29. printf("该数据的位置为:%d\n", searchPostDoubleLinkList(p, data));
  30. printf("请输入你要修改的数据的位置和数据:\n");
  31. scanf(" %d %d", &post, &data);
  32. changeDataDoubleLinkList(p, post, data);
  33. printf("修改数据以后的双向链表为:\n");
  34. showDoubleLinkList(p);
  35. printf("请输入你要删除的数据:\n");
  36. scanf(" %d", &data);
  37. deleteDataDoubleLinkList(p, data);
  38. printf("删除数据以后的双向链表为:\n");
  39. showDoubleLinkList(p);
  40. printf("双向链表的长度为:\n");
  41. printf("%d\n", lengthDoubleLinkList(p));
  42. return 0;
  43. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/959370
推荐阅读
相关标签
  

闽ICP备14008679号