数据结构(4)线性表之单循环链表

喜欢ヅ旅行 2023-08-17 16:50 273阅读 0赞

数据结构(4)线性表之单循环链表

      • 前言
      • 尾指针
      • 全部代码
        • SCList.h
        • SCList.cpp
        • Main.cpp

前言

所谓单循环链表,实际上就是在单链表的基础上,使最后一个结点的next指针再指向头结点,形成循环的效果。这样,从表中任何一个结点出发都可以找到其他结点的位置。

尾指针

顾名思义,尾指针是指向链表的最后一个结点。在单循环链表中,设立尾指针能使得一些操作简化,例如两个单循环链表的合并。

img\_2

img\_3

我们之前所写的管理结构,是既包括头指针又包括尾指针的,因此在实现某些操作时就很方便了。

单循环链表和单链表的实现思路、注意事项都是一样的,只是需要额外注意的是,在我们的管理结构中要注意保持last的next指针始终指向头结点,达到循环的效果。

附:单链表的实现思路及注意事项
数据结构(2.1)线性表之单链表的表示和实现
数据结构(2.2)线性表之单链表的具体实现

  • 链表为空

链表为空

  • 链表非空

链表非空

全部代码

单循环链表的各项操作与单链表并无差别,只是在判断链表结束的条件有差别,之前是判断next指针是否为空,现在需要判断是否为头结点。因此实现代码并没有巨大的改变,只是在一些判断条件上做出改变。

SCList.h

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

SCList.cpp

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

Main.cpp

  1. #include "SCList.h"
  2. int main(int argc, const char * argv[]) {
  3. List myList;
  4. InitSCList(&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 条评论,273人围观)

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

相关阅读