当前位置:   article > 正文

链表之双向链表的实现

链表之双向链表的实现

铁汁们大家好,我们上一篇博客学习了单链表,这节课让我们继续往深学习,学习一下双线链表,话不多说,我们开始吧!



目录

1.双向链表

2.顺序表和链表的优缺点

3.双向链表的实现


1.双向链表

1.我们要实现的双线链表是带头双向循环链表,它的结构最复杂,一般用在单独的存储数据。我们实际中使用的链表数据结构都是带头双向循环链表。

2.它虽然结构复杂,但是在我们用代码实现过程中,它比单链表简单。

3.相信很多铁汁不清楚双向链表的结构是什么,如下图:

2.顺序表和链表的优缺点

我们在这里总结一下这两种线性表,方便之后的学习。

顺序表:

优点:空间连续,支持随机访问

缺点:中间或前面部分的插入和删除,时间复杂度是O(n);

           增容很不方便,代价较大。

链表:

优点:任意位置的插入删除,时间复杂度为O(1);

           没有增容销耗,按需申请节点空间,不用了直接释放。

缺点:以节点为单位存储,不支持随机访问

3.双向链表的实现

经过上面的铺垫,我们来实现一个带头双向循环链表

List.h文件

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. #include<assert.h>
  5. #include<stdbool.h>
  6. typedef int ADataType;
  7. typedef struct ListNode
  8. {
  9. ADataType data;
  10. struct ListNode* prev;//双线链表前驱指针
  11. struct ListNode* next;//后继指针
  12. }LN;
  13. //双向链表初始化
  14. LN* ListInit();
  15. //为节点开辟空间
  16. LN* BuyListCapacity(ADataType x);
  17. //链表的销毁
  18. void ListDestory(LN* phead);
  19. //头插
  20. void ListPushFront(LN* phead, ADataType x);
  21. //尾插
  22. void ListPushBack(LN* phead, ADataType x);
  23. //打印
  24. void ListPrint(LN* phead);
  25. //头删
  26. void ListPopFront(LN* phead);
  27. //尾删
  28. void ListPopBack(LN* phead);
  29. //查找链表中的数据
  30. LN* ListSearch(LN* phead, ADataType x);
  31. //修改找到的数据
  32. void ListModify( LN* pos, ADataType y);
  33. //在这个位置后插入数据
  34. void ListInsert(LN* pos, ADataType x);
  35. //删除这个位置之后的数据
  36. void ListErase(LN* pos);
  37. //判断链表是否为空
  38. bool ListEmpty(LN* phead);

List.c文件

  1. #include"List.h"
  2. //为节点开辟空间
  3. LN* BuyListCapacity(ADataType x)
  4. {
  5. LN* newnode = (LN*)malloc(sizeof(LN));
  6. if (newnode == NULL)
  7. {
  8. perror("malloc is false!\n");
  9. exit(-1);
  10. }
  11. newnode->data = x;
  12. newnode->next = NULL;
  13. newnode->prev = NULL;
  14. return newnode;
  15. }
  16. //双向链表初始化
  17. LN* ListInit()
  18. {
  19. //开辟空间
  20. LN* phead = BuyListCapacity(0);
  21. //让头节点的前驱和后继都指向自己,是一个循环
  22. phead->next = phead;
  23. phead->prev = phead;
  24. return phead;
  25. }
  26. //链表的销毁
  27. void ListDestory(LN* phead)
  28. {
  29. assert(phead);
  30. LN* tail = phead->next;
  31. while (tail != phead)//链表的头尾相连,当尾等于头时,说明链表空了
  32. {
  33. LN* next = tail->next;
  34. free(tail);
  35. tail = next;
  36. }
  37. free(phead);
  38. phead = NULL;
  39. }
  40. //头插
  41. void ListPushFront(LN* phead, ADataType x)
  42. {
  43. assert(phead);
  44. LN* newnode = BuyListCapacity(x);
  45. //若这里不使用新的变量来存储原来第一个节点的值,就先链接后,在链接前
  46. newnode->next = phead->next;
  47. phead->next->prev = newnode;
  48. phead->next = newnode;
  49. newnode->prev = phead;
  50. }
  51. //尾插
  52. void ListPushBack(LN* phead, ADataType x)
  53. {
  54. assert(phead);
  55. LN* newnode = BuyListCapacity(x);
  56. //找到尾,进行插入节点
  57. LN* tail = phead->prev;
  58. tail->next = newnode;
  59. newnode->prev = tail;
  60. phead->prev = newnode;
  61. newnode->next = phead;
  62. }
  63. //打印
  64. void ListPrint(LN* phead)
  65. {
  66. assert(phead);
  67. LN* tail = phead->next;
  68. while (tail != phead)
  69. {
  70. printf(" %d ", tail->data);
  71. tail = tail->next;
  72. }
  73. printf("\n");
  74. }
  75. //头删
  76. void ListPopFront(LN* phead)
  77. {
  78. assert(phead);
  79. //判断链表是否为空,为空则删不了
  80. if (phead->next == phead)
  81. {
  82. printf("List is NULL!\n");
  83. return;
  84. }
  85. //先记录下后一个节点
  86. LN* first = phead->next;
  87. LN* second = first->next;
  88. phead->next = second;
  89. second->prev = phead;
  90. free(first);
  91. first = NULL;
  92. }
  93. //尾删
  94. void ListPopBack(LN* phead)
  95. {
  96. assert(phead);
  97. //判断链表是否为空
  98. if (phead->prev == phead)
  99. {
  100. printf("List is NULL!\n");
  101. return;
  102. }
  103. LN* tail = phead->prev;
  104. LN* prev = tail->prev;
  105. prev->next = phead;
  106. phead->prev = prev;
  107. free(tail);
  108. tail = NULL;
  109. }
  110. //查找链表中的数据
  111. LN* ListSearch(LN* phead, ADataType x)
  112. {
  113. assert(phead);
  114. LN* cur = phead->next;
  115. while (cur->data != x)
  116. {
  117. cur = cur->next;
  118. }
  119. if (cur->data == x)
  120. {
  121. return cur;
  122. }
  123. return NULL;
  124. }
  125. //修改找到的数据
  126. void ListModify( LN* pos, ADataType y)
  127. {
  128. assert(pos);
  129. pos->data = y;
  130. }
  131. //在这个位置后插入数据
  132. void ListInsert(LN* pos, ADataType x)
  133. {
  134. assert(pos);
  135. LN* newnode = BuyListCapacity(x);
  136. LN* next = pos->next;
  137. pos->next = newnode;
  138. newnode->prev = pos;
  139. newnode->next = next;
  140. next->prev = newnode;
  141. }
  142. //删除这个位置之后的数据
  143. void ListErase(LN* pos)
  144. {
  145. assert(pos);
  146. LN* cur = pos->next;
  147. LN* next = cur->next;
  148. pos->next = next;
  149. next->prev = pos;
  150. free(cur);
  151. cur = NULL;
  152. }
  153. //判断链表是否为空
  154. bool ListEmpty(LN* phead)
  155. {
  156. assert(phead);
  157. if (phead->prev == phead || phead->next == phead)
  158. {
  159. return true;
  160. }
  161. return false;
  162. }

Test.c文件

  1. #include"List.h"
  2. //带头双向循环链表的实现
  3. void Test1()
  4. {
  5. LN* head = ListInit();
  6. ListPushFront(head, 33);
  7. ListPushFront(head, 22);
  8. ListPushFront(head, 11);
  9. ListPushBack(head, 4);
  10. ListPushBack(head, 5);
  11. ListPushBack(head, 6);
  12. ListPushBack(head, 7);
  13. ListPushBack(head, 8);
  14. ListPushBack(head, 9);
  15. ListPushBack(head, 10);
  16. printf("ListNode:> ");
  17. ListPrint(head);
  18. ListPopFront(head);
  19. ListPopBack(head);
  20. printf("ListNode:> ");
  21. ListPrint(head);
  22. LN* pos = ListSearch(head, 7);
  23. if (pos == NULL)
  24. {
  25. printf("Not Find!\n");
  26. }
  27. else
  28. {
  29. printf("the number is %d\n", pos->data);
  30. ListModify(pos, 77);
  31. printf("ListNode:> ");
  32. ListPrint(head);
  33. ListInsert(pos, 13);
  34. ListInsert(pos, 14);
  35. ListInsert(pos, 15);
  36. printf("ListNode:> ");
  37. ListPrint(head);
  38. ListErase(pos);
  39. printf("ListNode:> ");
  40. ListPrint(head);
  41. }
  42. if (ListEmpty(head))
  43. {
  44. printf("List is NULL!\n");
  45. }
  46. else
  47. {
  48. printf("List is Notnull!\n");
  49. }
  50. ListDestory(head);
  51. printf("List is disory!\n");
  52. }
  53. int main()
  54. {
  55. Test1();
  56. return 0;
  57. }

结果:结果就是这样的,大家可以自己尝试一下!


这就是双向链表的实现,大家还是要自己敲一遍代码,帮助自己更好的掌握知识点。

谢谢铁汁们的支持,咱们下期再见!!!

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

闽ICP备14008679号