数据结构(6)线性表之双循环链表

矫情吗;* 2023-06-08 03:18 119阅读 0赞

数据结构(6)线性表之双循环链表

      • 前言
      • 双循环链表的插入与删除
      • 全部代码
        • DCList.h
        • DCList.cpp
        • Main.cpp

前言

同单链表一样,双向链表也可以是循环表。链表最后一个结点的next指针指向头结点,头结点的Prior指针指向最后一个结点,形成循环。

带头结点的空链表

img\_1

带头结点的非空链表

img\_2

添加管理结构

img\_3

双循环链表的插入与删除

实际上,在循环链表中,无论是头部插入还是尾部插入,都可以理解为按位置插入(就是在两个结点中间进行插入):头部插入是在头结点和首元结点之间进行插入,尾部插入则是在最后一个结点和头结点之间进行插入。这样,我们只需要知道如何在两个结点中间进行插入,就可以实现双循环链表诸多的插入操作。而如何在两个结点中间进行插入,跟在双链表中是一致的,也就是需要考虑四个指针的指向

  • 待插入结点的Prior指针
  • 待插入结点的Next指针
  • 待插入结点前驱的Next指针
  • 待插入结点后继的Prior指针

这样,本来区分开的头部插入、尾部插入操作可以整合为按位置插入,参数传要插入的位置即可。但是考虑到我们的双链表增加了管理结构,还需要保证管理结构指针的正确性,所以在代码中仍是区分实现的。

img\_4

尾部插入也是两个结点中的插入

img\_6

实际上

img\_5

插入与删除类似

img\_7
img\_8
其他操作同双链表一致,只是判断循环结束的条件有区别罢了,不细说

全部代码

DCList.h

  1. #ifndef DCList_h
  2. #define DCList_h
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <assert.h>
  6. #define ElemType int
  7. typedef struct Node{
  8. ElemType data;
  9. struct Node *prior;
  10. struct Node *next;
  11. }Node,*PNode;
  12. typedef struct List{
  13. PNode first;
  14. PNode last;
  15. int size;
  16. }List;
  17. //初始化
  18. void InitDCList(List *list);
  19. //1.尾部插入
  20. void push_back(List *list,ElemType x);
  21. //2.头部插入
  22. void push_fount(List *list,ElemType x);
  23. //3.展示
  24. void show_list(List *list);
  25. //4.尾部删除
  26. void pop_back(List *list);
  27. //5.头部删除
  28. void pop_fount(List *list);
  29. //6.按值插入(要求插入前的链表是有序的(此处为顺序
  30. void insert_val(List *list,ElemType x);
  31. //7.按值查找
  32. Node* find(List *list,ElemType x);
  33. //8.获取长度
  34. int length(List *list);
  35. //9.按值删除
  36. void delete_val(List *list,ElemType x);
  37. //10.排序
  38. void sort(List *list);
  39. //11.逆置(前后转换
  40. void resver(List *list);
  41. //12.清除单链表 ->只清除数据,保留头结点
  42. void clearList(List *list);
  43. //13.摧毁 ->包括头结点在内一起摧毁
  44. void destroy(List *list);
  45. //生成一个结点
  46. Node* getNode(ElemType x);
  47. #endif /* DCList_h */

DCList.cpp

  1. #include "DCList.h"
  2. //初始化
  3. void InitDCList(List *list){
  4. //申请头结点
  5. Node *s = (Node *)malloc(sizeof(Node));
  6. assert(s != NULL);
  7. list->first = list->last = s;
  8. //使链表循环
  9. list->first->prior = list->last;
  10. list->last->next = list->first;
  11. list->size = 0;
  12. }
  13. //1.尾部插入
  14. void push_back(List *list,ElemType x){
  15. Node *s = getNode(x);
  16. //s的前驱指向最后一个结点
  17. s->prior = list->last;
  18. //s的后继指向头结点
  19. s->next = list->last->next;
  20. //头结点的前驱指向s
  21. //list->last->next->prior = s;
  22. s->next->prior = s;
  23. //最后一个结点的后继指向s
  24. list->last->next = s;
  25. //重新设置last指针的值
  26. list->last = s;
  27. list->size ++;
  28. }
  29. //2.头部插入
  30. void push_fount(List *list,ElemType x){
  31. Node *s = getNode(x);
  32. //s的后继是头结点的后继
  33. s->next = list->first->next;
  34. //s的前驱是头结点
  35. s->prior = list->first;
  36. //原先第一个结点的前驱改为s
  37. //list->first->next->prior = s;
  38. s->next->prior = s;
  39. //头结点的后继改为s
  40. list->first->next = s;
  41. //判断是否是第一个结点
  42. if (list->first == list->last) {
  43. //是,需要修改last指针的指向
  44. list->last = s;
  45. }
  46. list->size ++;
  47. }
  48. //3.展示
  49. void show_list(List *list){
  50. Node *s = list->first->next;
  51. while (s != list->first) {
  52. printf("%4d",s->data);
  53. s = s->next;
  54. }
  55. printf("\n");
  56. }
  57. //4.尾部删除
  58. void pop_back(List *list){
  59. if (list->size == 0) {
  60. printf("链表已空!\n");
  61. return;
  62. }
  63. Node *s = list->last;
  64. //last指针修改为s的前驱
  65. //list->last = list->last->prior;
  66. list->last = s->prior;
  67. //s前驱的next指针指向s的后继(即头结点)
  68. //list->last->next = s->next;
  69. s->prior->next = s->next;
  70. //s后继的prior指针(即头结点的prior指针)指向s的前驱(即新的最后一个结点)
  71. //s->next->prior = list->last;
  72. s->next->prior = s->prior;
  73. //释放s
  74. free(s);
  75. list->size --;
  76. }
  77. //5.头部删除
  78. void pop_fount(List *list){
  79. if (list->size == 0) {
  80. printf("链表已空!\n");
  81. return;
  82. }
  83. Node *s = list->first->next;
  84. //s前驱的后继指向s的后继(即头结点的next指向s的next)
  85. //list->first->next = s->next;
  86. s->prior->next = s->next;
  87. //s后继的前驱指向s的前驱(即s的后继的prior指针指向头结点)
  88. //s->next->prior = list->first;
  89. s->next->prior = s->prior;
  90. //释放s
  91. free(s);
  92. //判断删除的是否是最后一个结点
  93. if (list->size == 1) {
  94. //是,重新修改last指针的指向
  95. list->last = list->first;
  96. }
  97. list->size -- ;
  98. }
  99. //6.按值插入(要求插入前的链表是有序的(此处为顺序
  100. void insert_val(List *list,ElemType x){
  101. Node *p = list->first;
  102. //寻找插入位置
  103. while (p->next != list->first && p->next->data < x) {
  104. p = p->next;
  105. }
  106. //在p结点之后进行插入
  107. //判断插入位置
  108. if (p->next == list->first) {
  109. //尾部插入
  110. push_back(list, x);
  111. }else{
  112. Node *s = getNode(x);
  113. //s的前驱为p
  114. s->prior = p;
  115. //s的后继为p的后继
  116. s->next = p->next;
  117. //p后继的前驱改为s
  118. p->next->prior = s;
  119. //p的后继改为s
  120. p->next = s;
  121. list->size ++;
  122. }
  123. }
  124. //7.按值查找
  125. Node* find(List *list,ElemType x){
  126. Node *s = list->first->next;
  127. while (s != list->first && s->data != x) {
  128. s = s->next;
  129. }
  130. if (s == list->first) {
  131. //循环结束,没找到
  132. return NULL;
  133. }
  134. return s;
  135. }
  136. //8.获取长度
  137. int length(List *list){
  138. return list->size;
  139. }
  140. //9.按值删除
  141. void delete_val(List *list,ElemType x){
  142. if (list->size == 0) {
  143. printf("链表已空!\n");
  144. return;
  145. }
  146. Node *p = find(list, x);
  147. if (p == NULL) {
  148. printf("要删除的数据不存在!\n");
  149. return;
  150. }
  151. //找到结点位置
  152. if (p == list->last) {
  153. //如果是最后一个,直接进行尾部删除
  154. push_back(list, x);
  155. }else{
  156. //p后继的前驱指向p的前驱
  157. p->next->prior = p->prior;
  158. //p前驱的后继指向p的后继
  159. p->prior->next = p->next;
  160. list->size --;
  161. }
  162. }
  163. //10.排序
  164. void sort(List *list){
  165. if (list->size <= 1) {
  166. printf("无须排序!\n");
  167. return;
  168. }
  169. //将链表分为两个部分,s单独作为一个链表,p指向后续结点
  170. Node *s = list->first->next;
  171. Node *p = s->next;
  172. //将后续结点的最后一个结点的next指针标记为空
  173. list->last->next = NULL;
  174. //重新设置last指针的值
  175. list->last = s;
  176. //让链表循环
  177. //s的后继指向头结点
  178. //list->last->next = list->first;
  179. s->next = list->first;
  180. //头结点的前驱指向s
  181. //list->first->prior = list->last;
  182. list->first->prior = s;
  183. while (p != NULL) {
  184. s = p;
  185. p = p->next;
  186. //直接进行按值插入
  187. insert_val(list, s->data);
  188. free(s);
  189. list->size --;
  190. }
  191. }
  192. //11.逆置(前后转换
  193. void resver(List *list){
  194. if (list->size <= 1) {
  195. printf("无须逆置!\n");
  196. return;
  197. }
  198. //将链表分为两个部分,s单独作为一个链表,p指向后续结点
  199. Node *s = list->first->next;
  200. Node *p = s->next;
  201. //将后续结点的最后一个结点的next指针标记为空
  202. list->last->next = NULL;
  203. //重新设置last指针的值
  204. list->last = s;
  205. //让链表循环
  206. //s的后继指向头结点
  207. //list->last->next = list->first;
  208. s->next = list->first;
  209. //头结点的前驱指向s
  210. //list->first->prior = list->last;
  211. list->first->prior = s;
  212. while (p != NULL) {
  213. s = p;
  214. p = p->next;
  215. //直接进行头部插入
  216. push_fount(list, s->data);
  217. free(s);
  218. list->size --;
  219. }
  220. }
  221. //12.清除单链表 ->只清除数据,保留头结点
  222. void clearList(List *list){
  223. if (list->size == 0) {
  224. return;
  225. }
  226. Node *s = list->first;
  227. Node *p = s->next;
  228. //遍历整个链表,释放结点
  229. while (p != list->first) {
  230. s = p;
  231. p = p->next;
  232. free(s);
  233. list->size --;
  234. }
  235. //重新设置last指针
  236. list->last = list->first;
  237. //使链表循环
  238. list->first->prior = list->last;
  239. list->last->next = list->first;
  240. }
  241. //13.摧毁 ->包括头结点在内一起摧毁
  242. void destroy(List *list){
  243. clearList(list);
  244. free(list->first);
  245. list->first = list->last = NULL;
  246. }
  247. //生成一个结点
  248. Node* getNode(ElemType x){
  249. //申请空间
  250. Node *s = (Node *)malloc(sizeof(Node));
  251. assert(s != NULL);
  252. //赋初值
  253. s->data = x;
  254. s->prior = s->next = NULL;
  255. //返回
  256. return s;
  257. }

Main.cpp

  1. #include "DCList.h"
  2. int main(int argc, const char * argv[]) {
  3. List myList;
  4. InitDCList(&myList);
  5. //保存要输入的数据
  6. ElemType item;
  7. //保存要查找的地址
  8. Node *p = NULL;
  9. int select = 1;
  10. while (select) {
  11. printf("**************************************\n");
  12. printf("* [1] push_back [2] push_front *\n");
  13. printf("* [3] show_list [4] pop_back *\n");
  14. printf("* [5] pop_front [6] insert_val *\n");
  15. printf("* [7] find [8] length *\n");
  16. printf("* [9] delete_val [10] sort *\n");
  17. printf("* [11] resver [12] clear *\n");
  18. printf("* [13*] destroy [0] quit_system*\n");
  19. printf("**************************************\n");
  20. printf("请选择:");
  21. scanf("%d",&select);
  22. if (select == 0) {
  23. break;
  24. }
  25. switch (select) {
  26. case 1:
  27. //尾部插入
  28. printf("请输入要插入的数据(-1结束):");
  29. scanf("%d",&item);
  30. while (item != -1) {
  31. push_back(&myList, item);
  32. scanf("%d",&item);
  33. }
  34. break;
  35. case 2:
  36. //头部插入
  37. printf("请输入要插入的数据(-1结束):");
  38. scanf("%d",&item);
  39. while (item != -1) {
  40. push_fount(&myList, item);
  41. scanf("%d",&item);
  42. }
  43. break;
  44. case 3:
  45. //展示单链表
  46. show_list(&myList);
  47. break;
  48. case 4:
  49. //尾部删除
  50. pop_back(&myList);
  51. break;
  52. case 5:
  53. //头部删除
  54. pop_fount(&myList);
  55. break;
  56. case 6:
  57. //按值插入
  58. printf("请输入要插入的数据:\n");
  59. scanf("%d",&item);
  60. insert_val(&myList, item);
  61. break;
  62. case 7:
  63. //按值查找
  64. printf("请输入要查找的值:\n");
  65. scanf("%d",&item);
  66. p = find(&myList, item);
  67. if (p == NULL) {
  68. printf("要查找的数据不存在!\n");
  69. }else{
  70. printf("地址为:%p\n",p);
  71. }
  72. break;
  73. case 8:
  74. //展示链表长度
  75. printf("链表的长度为:%d\n",length(&myList));
  76. break;
  77. case 9:
  78. //按值删除
  79. printf("请输入要删除的值:\n");
  80. scanf("%d",&item);
  81. delete_val(&myList, item);
  82. break;
  83. case 10:
  84. //排序
  85. sort(&myList);
  86. break;
  87. case 11:
  88. //逆置(前后转换
  89. resver(&myList);
  90. break;
  91. case 12:
  92. //清除
  93. clearList(&myList);
  94. break;
  95. case 13:
  96. destroy(&myList);
  97. break;
  98. default:
  99. printf("输入的命令有误,请重新插入\n");
  100. break;
  101. }
  102. }
  103. return 0;
  104. }

发表评论

表情:
评论列表 (有 0 条评论,119人围观)

还没有评论,来说两句吧...

相关阅读