当前位置:   article > 正文

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】链表—双向链表

【海贼王的数据航海:利用数据结构成为数据海洋的霸主】链表—双向链表

目录

往期

1 -> 带头+双向+循环链表(双链表)

1.1 -> 接口声明

1.2 -> 接口实现

1.2.1 -> 双向链表初始化

1.2.2 -> 动态申请一个结点

1.2.3 -> 双向链表销毁

1.2.4 -> 双向链表打印

1.2.5 -> 双向链表判空

1.2.6 -> 双向链表尾插

1.2.7 -> 双向链表尾删

1.2.8 -> 双向链表头插

1.2.9 -> 双向链表头删

1.2.10 -> 双向链表查找

1.2.11 ->  双向链表在pos的前面进行插入

1.2.12 -> 双向链表删除pos位置的节点

2 -> 顺序表和链表的区别

3 -> 完整代码

3.1 -> List.c

3.2 -> List.h

3.3 -> Test.c


往期

链表-单链表

1 -> 带头+双向+循环链表(双链表)

1.1 -> 接口声明

  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include <stdbool.h>
  7. // 带头+双向+循环链表增删查改实现
  8. typedef int LTDataType;
  9. typedef struct LTNode
  10. {
  11. LTDataType data;
  12. struct LTNode* next;
  13. struct LTNode* prev;
  14. }LTNode;
  15. // 双向链表初始化
  16. LTNode* LTInit();
  17. // 动态申请一个结点
  18. LTNode* BuyLTNode(LTDataType x);
  19. // 双向链表销毁
  20. void LTDestory(LTNode* phead);
  21. // 双向链表打印
  22. void LTPrint(LTNode* phead);
  23. // 双向链表判空
  24. bool LTEmpty(LTNode* phead);
  25. // 双向链表尾插
  26. void LTPushBack(LTNode* phead, LTDataType x);
  27. // 双向链表尾删
  28. void LTPopBack(LTNode* phead);
  29. // 双向链表头插
  30. void LTPushFront(LTNode* phead, LTDataType x);
  31. // 双向链表头删
  32. void LTPopFront(LTNode* phead);
  33. // 双向链表查找
  34. LTNode* LTFind(LTNode* phead, LTDataType x);
  35. // 双向链表在pos的前面进行插入
  36. void LTInsert(LTNode* pos, LTDataType x);
  37. // 双向链表删除pos位置的节点
  38. void LTErase(LTNode* pos);

1.2 -> 接口实现

1.2.1 -> 双向链表初始化

  1. // 双向链表初始化
  2. LTNode* LTInit()
  3. {
  4. LTNode* phead = BuyLTNode(-1);
  5. phead->next = phead;
  6. phead->prev = phead;
  7. return phead;
  8. }

1.2.2 -> 动态申请一个结点

  1. // 动态申请一个结点
  2. LTNode* BuyLTNode(LTDataType x)
  3. {
  4. LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
  5. if (newnode == NULL)
  6. {
  7. perror("malloc fail");
  8. return NULL;
  9. }
  10. newnode->data = x;
  11. newnode->next = NULL;
  12. newnode->prev = NULL;
  13. return newnode;
  14. }

1.2.3 -> 双向链表销毁

  1. // 双向链表销毁
  2. void LTDestory(LTNode* phead)
  3. {
  4. assert(phead);
  5. LTNode* cur = phead->next;
  6. while (cur != phead)
  7. {
  8. LTNode* next = cur->next;
  9. free(cur);
  10. cur = next;
  11. }
  12. free(phead);
  13. }

1.2.4 -> 双向链表打印

  1. // 双向链表打印
  2. void LTPrint(LTNode* phead)
  3. {
  4. assert(phead);
  5. printf("guard<==>");
  6. LTNode* cur = phead->next;
  7. while (cur != phead)
  8. {
  9. printf("%d<==>", cur->data);
  10. cur = cur->next;
  11. }
  12. printf("\n");
  13. }

1.2.5 -> 双向链表判空

  1. // 双向链表判空
  2. bool LTEmpty(LTNode* phead)
  3. {
  4. assert(phead);
  5. return phead->next == phead;
  6. }

1.2.6 -> 双向链表尾插

  1. // 双向链表尾插
  2. void LTPushBack(LTNode* phead, LTDataType x)
  3. {
  4. assert(phead);
  5. LTNode* tail = phead->prev;
  6. LTNode* newnode = BuyLTNode(x);
  7. tail->next = newnode;
  8. newnode->prev = tail;
  9. newnode->next = phead;
  10. phead->prev = newnode;
  11. // 复用
  12. // LTInsert(phead, x);
  13. }
  1. // 尾插测试
  2. void Test1()
  3. {
  4. LTNode* plist = LTInit();
  5. LTPushBack(plist, 1);
  6. LTPushBack(plist, 2);
  7. LTPushBack(plist, 3);
  8. LTPushBack(plist, 4);
  9. LTPushBack(plist, 5);
  10. LTPrint(plist);
  11. LTDestory(plist);
  12. plist = NULL;
  13. }

 

1.2.7 -> 双向链表尾删

  1. // 双向链表尾删
  2. void LTPopBack(LTNode* phead)
  3. {
  4. assert(phead);
  5. assert(!LTEmpty(phead));
  6. LTNode* tail = phead->prev;
  7. LTNode* tailPrev = tail->prev;
  8. free(tail);
  9. tailPrev->next = phead;
  10. phead->prev = tailPrev;
  11. // 复用
  12. // LTErase(phead->prev);
  13. }
  1. // 尾删测试
  2. void Test2()
  3. {
  4. LTNode* plist = LTInit();
  5. LTPushBack(plist, 1);
  6. LTPushBack(plist, 2);
  7. LTPushBack(plist, 3);
  8. LTPushBack(plist, 4);
  9. LTPushBack(plist, 5);
  10. LTPrint(plist);
  11. LTPopBack(plist);
  12. LTPrint(plist);
  13. LTPopBack(plist);
  14. LTPrint(plist);
  15. LTPopBack(plist);
  16. LTPrint(plist);
  17. LTPopBack(plist);
  18. LTPrint(plist);
  19. LTPopBack(plist);
  20. LTPrint(plist);
  21. LTDestory(plist);
  22. plist = NULL;
  23. }

1.2.8 -> 双向链表头插

  1. // 双向链表头插
  2. void LTPushFront(LTNode* phead, LTDataType x)
  3. {
  4. assert(phead);
  5. LTNode* newnode = BuyLTNode(x);
  6. newnode->next = phead->next;
  7. phead->next->prev = newnode;
  8. phead->next = newnode;
  9. newnode->prev = phead;
  10. // 复用
  11. // LTInsert(phead->next, x);
  12. }
  1. // 头插测试
  2. void Test3()
  3. {
  4. LTNode* plist = LTInit();
  5. LTPushFront(plist, 1);
  6. LTPushFront(plist, 2);
  7. LTPushFront(plist, 3);
  8. LTPushFront(plist, 4);
  9. LTPushFront(plist, 5);
  10. LTPrint(plist);
  11. LTDestory(plist);
  12. plist = NULL;
  13. }

1.2.9 -> 双向链表头删

  1. // 双向链表头删
  2. void LTPopFront(LTNode* phead)
  3. {
  4. assert(phead);
  5. assert(!LTEmpty(phead));
  6. LTNode* first = phead->next;
  7. LTNode* second = first->next;
  8. phead->next = second;
  9. second->prev = phead;
  10. free(first);
  11. // 复用
  12. // LTErase(phead->next);
  13. }
  1. // 头删测试
  2. void Test4()
  3. {
  4. LTNode* plist = LTInit();
  5. LTPushBack(plist, 1);
  6. LTPushBack(plist, 2);
  7. LTPushBack(plist, 3);
  8. LTPushBack(plist, 4);
  9. LTPushBack(plist, 5);
  10. LTPrint(plist);
  11. LTPopFront(plist);
  12. LTPrint(plist);
  13. LTPopFront(plist);
  14. LTPrint(plist);
  15. LTPopFront(plist);
  16. LTPrint(plist);
  17. LTPopFront(plist);
  18. LTPrint(plist);
  19. LTPopFront(plist);
  20. LTPrint(plist);
  21. LTDestory(plist);
  22. plist = NULL;
  23. }

1.2.10 -> 双向链表查找

  1. // 双向链表查找
  2. LTNode* LTFind(LTNode* phead, LTDataType x)
  3. {
  4. assert(phead);
  5. LTNode* cur = phead->next;
  6. while (cur != phead)
  7. {
  8. if (cur->data == x)
  9. {
  10. return cur;
  11. }
  12. cur = cur->next;
  13. }
  14. return NULL;
  15. }

1.2.11 ->  双向链表在pos的前面进行插入

  1. // 双向链表在pos的前面进行插入
  2. void LTInsert(LTNode* pos, LTDataType x)
  3. {
  4. assert(pos);
  5. LTNode* prev = pos->prev;
  6. LTNode* newnode = BuyLTNode(x);
  7. prev->next = newnode;
  8. newnode->prev = prev;
  9. newnode->next = pos;
  10. pos->prev = newnode;
  11. }
  1. // 查找插入测试
  2. void Test5()
  3. {
  4. LTNode* plist = LTInit();
  5. LTPushBack(plist, 1);
  6. LTPushBack(plist, 2);
  7. LTPushBack(plist, 3);
  8. LTPushBack(plist, 4);
  9. LTPushBack(plist, 5);
  10. LTPrint(plist);
  11. LTNode* pos = LTFind(plist, 3);
  12. if (pos)
  13. LTInsert(pos, 99);
  14. LTPrint(plist);
  15. LTDestory(plist);
  16. plist = NULL;
  17. }

1.2.12 -> 双向链表删除pos位置的节点

  1. // 双向链表删除pos位置的节点
  2. void LTErase(LTNode* pos)
  3. {
  4. assert(pos);
  5. LTNode* posPrev = pos->prev;
  6. LTNode* posNext = pos->next;
  7. posPrev->next = posNext;
  8. posNext->prev = posPrev;
  9. free(pos);
  10. }

2 -> 顺序表和链表的区别

不同点顺序表链表
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
任意位置插入或者删除元素可能需要搬移元素,效率低O(N)只需修改指针指向
插入动态顺序表,空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁
缓存利用率

注:缓存利用率参考存储体系结构以及局部原理性。

3 -> 完整代码

3.1 -> List.c

  1. #include "List.h"
  2. // 双向链表初始化
  3. LTNode* LTInit()
  4. {
  5. LTNode* phead = BuyLTNode(-1);
  6. phead->next = phead;
  7. phead->prev = phead;
  8. return phead;
  9. }
  10. // 动态申请一个结点
  11. LTNode* BuyLTNode(LTDataType x)
  12. {
  13. LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
  14. if (newnode == NULL)
  15. {
  16. perror("malloc fail");
  17. return NULL;
  18. }
  19. newnode->data = x;
  20. newnode->next = NULL;
  21. newnode->prev = NULL;
  22. return newnode;
  23. }
  24. // 双向链表销毁
  25. void LTDestory(LTNode* phead)
  26. {
  27. assert(phead);
  28. LTNode* cur = phead->next;
  29. while (cur != phead)
  30. {
  31. LTNode* next = cur->next;
  32. free(cur);
  33. cur = next;
  34. }
  35. free(phead);
  36. }
  37. // 双向链表打印
  38. void LTPrint(LTNode* phead)
  39. {
  40. assert(phead);
  41. printf("guard<==>");
  42. LTNode* cur = phead->next;
  43. while (cur != phead)
  44. {
  45. printf("%d<==>", cur->data);
  46. cur = cur->next;
  47. }
  48. printf("\n");
  49. }
  50. // 双向链表判空
  51. bool LTEmpty(LTNode* phead)
  52. {
  53. assert(phead);
  54. return phead->next == phead;
  55. }
  56. // 双向链表尾插
  57. void LTPushBack(LTNode* phead, LTDataType x)
  58. {
  59. assert(phead);
  60. LTNode* tail = phead->prev;
  61. LTNode* newnode = BuyLTNode(x);
  62. tail->next = newnode;
  63. newnode->prev = tail;
  64. newnode->next = phead;
  65. phead->prev = newnode;
  66. // 复用
  67. // LTInsert(phead, x);
  68. }
  69. // 双向链表尾删
  70. void LTPopBack(LTNode* phead)
  71. {
  72. assert(phead);
  73. assert(!LTEmpty(phead));
  74. LTNode* tail = phead->prev;
  75. LTNode* tailPrev = tail->prev;
  76. free(tail);
  77. tailPrev->next = phead;
  78. phead->prev = tailPrev;
  79. // 复用
  80. // LTErase(phead->prev);
  81. }
  82. // 双向链表头插
  83. void LTPushFront(LTNode* phead, LTDataType x)
  84. {
  85. assert(phead);
  86. LTNode* newnode = BuyLTNode(x);
  87. newnode->next = phead->next;
  88. phead->next->prev = newnode;
  89. phead->next = newnode;
  90. newnode->prev = phead;
  91. // 复用
  92. // LTInsert(phead->next, x);
  93. }
  94. // 双向链表头删
  95. void LTPopFront(LTNode* phead)
  96. {
  97. assert(phead);
  98. assert(!LTEmpty(phead));
  99. LTNode* first = phead->next;
  100. LTNode* second = first->next;
  101. phead->next = second;
  102. second->prev = phead;
  103. free(first);
  104. // 复用
  105. // LTErase(phead->next);
  106. }
  107. // 双向链表查找
  108. LTNode* LTFind(LTNode* phead, LTDataType x)
  109. {
  110. assert(phead);
  111. LTNode* cur = phead->next;
  112. while (cur != phead)
  113. {
  114. if (cur->data == x)
  115. {
  116. return cur;
  117. }
  118. cur = cur->next;
  119. }
  120. return NULL;
  121. }
  122. // 双向链表在pos的前面进行插入
  123. void LTInsert(LTNode* pos, LTDataType x)
  124. {
  125. assert(pos);
  126. LTNode* prev = pos->prev;
  127. LTNode* newnode = BuyLTNode(x);
  128. prev->next = newnode;
  129. newnode->prev = prev;
  130. newnode->next = pos;
  131. pos->prev = newnode;
  132. }
  133. // 双向链表删除pos位置的节点
  134. void LTErase(LTNode* pos)
  135. {
  136. assert(pos);
  137. LTNode* posPrev = pos->prev;
  138. LTNode* posNext = pos->next;
  139. posPrev->next = posNext;
  140. posNext->prev = posPrev;
  141. free(pos);
  142. }

3.2 -> List.h

  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS 1
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #include <stdbool.h>
  7. // 带头+双向+循环链表增删查改实现
  8. typedef int LTDataType;
  9. typedef struct LTNode
  10. {
  11. LTDataType data;
  12. struct LTNode* next;
  13. struct LTNode* prev;
  14. }LTNode;
  15. // 双向链表初始化
  16. LTNode* LTInit();
  17. // 动态申请一个结点
  18. LTNode* BuyLTNode(LTDataType x);
  19. // 双向链表销毁
  20. void LTDestory(LTNode* phead);
  21. // 双向链表打印
  22. void LTPrint(LTNode* phead);
  23. // 双向链表判空
  24. bool LTEmpty(LTNode* phead);
  25. // 双向链表尾插
  26. void LTPushBack(LTNode* phead, LTDataType x);
  27. // 双向链表尾删
  28. void LTPopBack(LTNode* phead);
  29. // 双向链表头插
  30. void LTPushFront(LTNode* phead, LTDataType x);
  31. // 双向链表头删
  32. void LTPopFront(LTNode* phead);
  33. // 双向链表查找
  34. LTNode* LTFind(LTNode* phead, LTDataType x);
  35. // 双向链表在pos的前面进行插入
  36. void LTInsert(LTNode* pos, LTDataType x);
  37. // 双向链表删除pos位置的节点
  38. void LTErase(LTNode* pos);

3.3 -> Test.c

  1. #include "List.h"
  2. // 尾插测试
  3. void Test1()
  4. {
  5. LTNode* plist = LTInit();
  6. LTPushBack(plist, 1);
  7. LTPushBack(plist, 2);
  8. LTPushBack(plist, 3);
  9. LTPushBack(plist, 4);
  10. LTPushBack(plist, 5);
  11. LTPrint(plist);
  12. LTDestory(plist);
  13. plist = NULL;
  14. }
  15. // 尾删测试
  16. void Test2()
  17. {
  18. LTNode* plist = LTInit();
  19. LTPushBack(plist, 1);
  20. LTPushBack(plist, 2);
  21. LTPushBack(plist, 3);
  22. LTPushBack(plist, 4);
  23. LTPushBack(plist, 5);
  24. LTPrint(plist);
  25. LTPopBack(plist);
  26. LTPrint(plist);
  27. LTPopBack(plist);
  28. LTPrint(plist);
  29. LTPopBack(plist);
  30. LTPrint(plist);
  31. LTPopBack(plist);
  32. LTPrint(plist);
  33. LTPopBack(plist);
  34. LTPrint(plist);
  35. LTDestory(plist);
  36. plist = NULL;
  37. }
  38. // 头插测试
  39. void Test3()
  40. {
  41. LTNode* plist = LTInit();
  42. LTPushFront(plist, 1);
  43. LTPushFront(plist, 2);
  44. LTPushFront(plist, 3);
  45. LTPushFront(plist, 4);
  46. LTPushFront(plist, 5);
  47. LTPrint(plist);
  48. LTDestory(plist);
  49. plist = NULL;
  50. }
  51. // 头删测试
  52. void Test4()
  53. {
  54. LTNode* plist = LTInit();
  55. LTPushBack(plist, 1);
  56. LTPushBack(plist, 2);
  57. LTPushBack(plist, 3);
  58. LTPushBack(plist, 4);
  59. LTPushBack(plist, 5);
  60. LTPrint(plist);
  61. LTPopFront(plist);
  62. LTPrint(plist);
  63. LTPopFront(plist);
  64. LTPrint(plist);
  65. LTPopFront(plist);
  66. LTPrint(plist);
  67. LTPopFront(plist);
  68. LTPrint(plist);
  69. LTPopFront(plist);
  70. LTPrint(plist);
  71. LTDestory(plist);
  72. plist = NULL;
  73. }
  74. // 查找插入测试
  75. void Test5()
  76. {
  77. LTNode* plist = LTInit();
  78. LTPushBack(plist, 1);
  79. LTPushBack(plist, 2);
  80. LTPushBack(plist, 3);
  81. LTPushBack(plist, 4);
  82. LTPushBack(plist, 5);
  83. LTPrint(plist);
  84. LTNode* pos = LTFind(plist, 3);
  85. if (pos)
  86. LTInsert(pos, 99);
  87. LTPrint(plist);
  88. LTDestory(plist);
  89. plist = NULL;
  90. }
  91. int main()
  92. {
  93. return 0;
  94. }

感谢大佬们支持!!!

互三啦!!!

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

闽ICP备14008679号