当前位置:   article > 正文

暴力数据结构之单链表专题

暴力数据结构之单链表专题

1. 单链表的初始化

首先定义节点的结构,然后动态内存申请一部分空间,每一个节点都有一个值以及指向下一个节点的指针,称作值域和指针域。 

  1. //定义节点的结构
  2. //数据 + 指向下一个节点的指针
  3. typedef int SLTDataType;
  4. typedef struct SListNode
  5. {
  6. SLTDataType data;
  7. struct SListNode* next;
  8. }SLTNode;

初始化需要为链表节点动态申请一块空间,然后对值域和指针域初始化。

  1. //初始化函数
  2. SLTNode* SLTBuyNode(SLTDataType x)
  3. {
  4. SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  5. if (newnode == NULL)
  6. {
  7. perror("malloc fail!");
  8. exit(1);
  9. }
  10. newnode->data = x;
  11. newnode->next = NULL;
  12. return newnode;
  13. }

2. 单链表的相关函数

2.1 头插和头删

首先断言头结点不能为空,然后直接从表头插入节点。

  1. //头插函数
  2. void SLTPushFront(SLTNode** pphead, SLTDataType x)
  3. {
  4. assert(pphead);
  5. SLTNode* newnode = SLTBuyNode(x);
  6. //newnode *pphead
  7. //将链表依次后移,从头插入
  8. newnode->next = *pphead;
  9. *pphead = newnode;
  10. }

断言判断头结点及其地址都不为空,然后将原头结点的下一个节点保存起来,释放原来的头结点,则原头结点的下一个节点成为新的头结点。

  1. //头删函数
  2. void SLTPopFront(SLTNode** pphead)
  3. {
  4. assert(pphead && *pphead);
  5. SLTNode* next = (*pphead)->next;
  6. free(*pphead);
  7. *pphead = next;
  8. }
2.2 尾插和尾删

断言头结点不能为空,同样插入,但是要判断原链表是否为空链表,是空链表则直接插入,反之遍历链表找到尾节点再插入。

  1. //尾插函数
  2. void SLTPushBack(SLTNode** pphead, SLTDataType x)
  3. {
  4. assert(pphead);
  5. //*pphead 就是指向第一个节点的指针
  6. //空链表和非空链表
  7. SLTNode* newnode = SLTBuyNode(x);
  8. if (*pphead == NULL)
  9. {
  10. *pphead = newnode;
  11. }
  12. else
  13. {
  14. //找尾
  15. SLTNode* ptail = *pphead;
  16. while (ptail->next)
  17. {
  18. ptail = ptail->next;
  19. }
  20. //ptail指向的是尾节点
  21. ptail->next = newnode;
  22. }
  23. }

断言判断头结点及其地址均不为空,同样的原链表如果只有一个节点则直接释放,反之找到尾节点后释放尾节点。

  1. //尾删函数
  2. void SLTPopBack(SLTNode** pphead)
  3. {
  4. //链表不能为空
  5. assert(pphead && *pphead);
  6. //考虑链表只有一个节点的情况
  7. if ((*pphead)->next == NULL)
  8. {
  9. free(pphead);
  10. pphead = NULL;
  11. }
  12. else
  13. {
  14. SLTNode* prev = *pphead;
  15. SLTNode* ptail = *pphead;
  16. while (ptail->next)
  17. {
  18. prev = ptail;
  19. ptail = ptail->next;
  20. }
  21. free(ptail);
  22. ptail = NULL;
  23. prev->next = NULL;
  24. }
  25. }
2.3 在指定位置的前后插入数据

断言待插入节点位置、头结点及其地址均不为空,如果pos为头结点就直接头插,反之遍历链表找到pos的上一个节点,然后在二者中间插入。

  1. //在指定位置之前插入数据
  2. void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
  3. {
  4. assert(pos);
  5. assert(pphead && *pphead);
  6. SLTNode* newnode = SLTBuyNode(x);
  7. //判断是否为头节点
  8. if (pos == *pphead)
  9. {
  10. SLTPushFront(pphead, x);
  11. }
  12. else
  13. {
  14. SLTNode* prev = *pphead;
  15. while (prev->next != pos)
  16. {
  17. prev = prev->next;
  18. }
  19. newnode->next = pos;
  20. prev->next = newnode;
  21. }
  22. }

断言待插入节点位置、头结点及其地址均不为空,找到pos的上一个节点,然后在二者中间插入。 

  1. //在指定位置之后插入数据
  2. void SLTInsertAfter(SLTNode* pos, SLTDataType x)
  3. {
  4. assert(pos);
  5. SLTNode* newnode = SLTBuyNode(x);
  6. newnode->next = pos->next;
  7. pos->next = newnode;
  8. }
2.4 删除当前节点或后面节点

 断言待插入节点位置、头结点及其地址均不为空,如果pos为头结点直接头删,反之遍历链表找     到pos节点后保存相邻节点,释放pos节点,将相邻节点连接起来形成新链表。

  1. //删除pos当前指向的节点
  2. void SLTErase(SLTNode** pphead, SLTNode* pos)
  3. {
  4. assert(pphead && *pphead);
  5. assert(pos);
  6. //pos是头结点/不是头结点
  7. if (pos == *pphead)
  8. {
  9. //头删
  10. SLTPopFront(pphead);
  11. }
  12. else
  13. {
  14. SLTNode* prev = *pphead;
  15. while (prev->next != pos)
  16. {
  17. prev = prev->next;
  18. }
  19. prev->next = pos->next;
  20. free(pos);
  21. pos = NULL;
  22. }
  23. }

断言待插入节点位置及其下一个节点均不为空,保存pos下一个节点即待删除节点,释放pos节点,将相邻节点连接起来形成新链表。

  1. //删除pos之后的节点
  2. void SLTErase(SLTNode* pos)
  3. {
  4. assert(pos && pos->next);
  5. SLTNode* del = pos->next;
  6. pos = del->next;
  7. free(del);
  8. del = NULL;
  9. }
2.5 销毁和查找 

遍历链表找符合的节点,然后直接返回该节点。

  1. //查找
  2. SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
  3. {
  4. SLTNode* pcur = phead;
  5. while (pcur != NULL)
  6. {
  7. if (pcur->data == x)
  8. {
  9. return pcur;
  10. }
  11. pcur = pcur->next;
  12. }
  13. //pcur == NULL;
  14. return NULL;
  15. }

由于前面有动态内存申请,所以要进行释放free掉,就有了销毁函数。 

  1. //销毁链表
  2. void SLTDesTroy(SLTNode** pphead)
  3. {
  4. assert(pphead && *pphead);
  5. SLTNode* pcur = *pphead;
  6. while (pcur)
  7. {
  8. SLTNode* next = pcur->next;
  9. free(pcur);
  10. pcur = next;
  11. }
  12. *pphead = NULL;
  13. }

3. 代码展示(可自行复制调试)

3.1 test.c
  1. #include"SList.h"
  2. void SListTest01()
  3. {
  4. //链表是由一个一个的节点组成
  5. //创建几个节点
  6. SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));
  7. node1->data = 1;
  8. SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));
  9. node2->data = 2;
  10. SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));
  11. node3->data = 3;
  12. SLTNode* node4 = (SLTNode*)malloc(sizeof(SLTNode));
  13. node4->data = 4;
  14. //将四个节点连接起来
  15. node1->next = node2;
  16. node2->next = node3;
  17. node3->next = node4;
  18. node4->next = NULL;
  19. //调用链表的打印
  20. SLTNode* plist = node1;
  21. SLTPrint(plist);
  22. }
  23. void SListTest02()
  24. {
  25. SLTNode* plist = NULL;
  26. SLTPushBack(&plist, 1);
  27. SLTPushBack(&plist, 2);
  28. SLTPushBack(&plist, 3);
  29. SLTPushBack(&plist, 4);
  30. SLTPrint(plist);
  31. //SLTPushBack(NULL, 5);
  32. //
  33. //测试头插
  34. //SLTPushFront(&plist, 6);
  35. //SLTPrint(plist);
  36. //SLTPushFront(&plist, 7);
  37. //SLTPrint(plist);
  38. //SLTPushFront(&plist, 8);
  39. //SLTPrint(plist);
  40. //测试尾删
  41. SLTPopBack(&plist);
  42. SLTPrint(plist);
  43. SLTPopBack(&plist);
  44. SLTPrint(plist);
  45. SLTPopBack(&plist);
  46. SLTPrint(plist);
  47. }
  48. int main()
  49. {
  50. //SListTest01();
  51. SListTest02();
  52. return 0;
  53. }
3.2 SList.h
  1. #pragma once
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<assert.h>
  6. //定义节点的结构
  7. //数据 + 指向下一个节点的指针
  8. typedef int SLTDataType;
  9. typedef struct SListNode
  10. {
  11. SLTDataType data;
  12. struct SListNode* next;
  13. }SLTNode;
  14. //打印函数
  15. void SLTPrint(SLTNode* phead);
  16. //初始化函数
  17. SLTNode* SLTBuyNode(SLTDataType x);
  18. //头插函数
  19. void SLTPushFront(SLTNode** pphead, SLTDataType x);
  20. //尾插函数
  21. void SLTPushBack(SLTNode** pphead, SLTDataType x);
  22. //头删函数
  23. void SLTPopFront(SLTNode** pphead);
  24. //尾删函数
  25. void SLTPopBack(SLTNode** pphead);
  26. //删除pos之后的节点
  27. void SLTErase(SLTNode* pos);
  28. //销毁链表
  29. void SLTDesTroy(SLTNode** pphead);
3.3 SList.c 
  1. #include"SList.h"
  2. //打印函数
  3. void SLTPrint(SLTNode* phead)
  4. {
  5. SLTNode* pcur = phead;
  6. while (pcur)
  7. {
  8. printf("->%d", pcur->data);
  9. pcur = pcur->next;
  10. }
  11. printf("->NULL\n");
  12. }
  13. //初始化函数
  14. SLTNode* SLTBuyNode(SLTDataType x)
  15. {
  16. SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
  17. if (newnode == NULL)
  18. {
  19. perror("malloc fail!");
  20. exit(1);
  21. }
  22. newnode->data = x;
  23. newnode->next = NULL;
  24. return newnode;
  25. }
  26. //头插函数
  27. void SLTPushFront(SLTNode** pphead, SLTDataType x)
  28. {
  29. assert(pphead);
  30. SLTNode* newnode = SLTBuyNode(x);
  31. //newnode *pphead
  32. //将链表依次后移,从头插入
  33. newnode->next = *pphead;
  34. *pphead = newnode;
  35. }
  36. //尾插函数
  37. void SLTPushBack(SLTNode** pphead, SLTDataType x)
  38. {
  39. assert(pphead);
  40. //*pphead 就是指向第一个节点的指针
  41. //空链表和非空链表
  42. SLTNode* newnode = SLTBuyNode(x);
  43. if (*pphead == NULL)
  44. {
  45. *pphead = newnode;
  46. }
  47. else
  48. {
  49. //找尾
  50. SLTNode* ptail = *pphead;
  51. while (ptail->next)
  52. {
  53. ptail = ptail->next;
  54. }
  55. //ptail指向的是尾节点
  56. ptail->next = newnode;
  57. }
  58. }
  59. //尾删函数
  60. void SLTPopBack(SLTNode** pphead)
  61. {
  62. //链表不能为空
  63. assert(pphead && *pphead);
  64. //考虑链表只有一个节点的情况
  65. if ((*pphead)->next == NULL)
  66. {
  67. free(pphead);
  68. pphead = NULL;
  69. }
  70. else
  71. {
  72. SLTNode* prev = *pphead;
  73. SLTNode* ptail = *pphead;
  74. while (ptail->next)
  75. {
  76. prev = ptail;
  77. ptail = ptail->next;
  78. }
  79. free(ptail);
  80. ptail = NULL;
  81. prev->next = NULL;
  82. }
  83. }
  84. //头删函数
  85. void SLTPopFront(SLTNode** pphead)
  86. {
  87. assert(pphead && *pphead);
  88. SLTNode* next = (*pphead)->next;
  89. free(*pphead);
  90. *pphead = next;
  91. }
  92. //查找
  93. SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
  94. {
  95. SLTNode* pcur = phead;
  96. while (pcur != NULL)
  97. {
  98. if (pcur->data == x)
  99. {
  100. return pcur;
  101. }
  102. pcur = pcur->next;
  103. }
  104. //pcur == NULL;
  105. return NULL;
  106. }
  107. //在指定位置之前插入数据
  108. void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
  109. {
  110. assert(pos);
  111. assert(pphead && *pphead);
  112. SLTNode* newnode = SLTBuyNode(x);
  113. //判断是否为头节点
  114. if (pos == *pphead)
  115. {
  116. SLTPushFront(pphead, x);
  117. }
  118. else
  119. {
  120. SLTNode* prev = *pphead;
  121. while (prev->next != pos)
  122. {
  123. prev = prev->next;
  124. }
  125. newnode->next = pos;
  126. prev->next = newnode;
  127. }
  128. }
  129. //在指定位置之后插入数据
  130. void SLTInsertAfter(SLTNode* pos, SLTDataType x)
  131. {
  132. assert(pos);
  133. SLTNode* newnode = SLTBuyNode(x);
  134. newnode->next = pos->next;
  135. pos->next = newnode;
  136. }
  137. //删除pos当前指向的节点
  138. void SLTErase(SLTNode** pphead, SLTNode* pos)
  139. {
  140. assert(pphead && *pphead);
  141. assert(pos);
  142. //pos是头结点/不是头结点
  143. if (pos == *pphead)
  144. {
  145. //头删
  146. SLTPopFront(pphead);
  147. }
  148. else
  149. {
  150. SLTNode* prev = *pphead;
  151. while (prev->next != pos)
  152. {
  153. prev = prev->next;
  154. }
  155. prev->next = pos->next;
  156. free(pos);
  157. pos = NULL;
  158. }
  159. }
  160. //删除pos之后的节点
  161. void SLTErase(SLTNode* pos)
  162. {
  163. assert(pos && pos->next);
  164. SLTNode* del = pos->next;
  165. pos = del->next;
  166. free(del);
  167. del = NULL;
  168. }
  169. //销毁链表
  170. void SLTDesTroy(SLTNode** pphead)
  171. {
  172. assert(pphead && *pphead);
  173. SLTNode* pcur = *pphead;
  174. while (pcur)
  175. {
  176. SLTNode* next = pcur->next;
  177. free(pcur);
  178. pcur = next;
  179. }
  180. *pphead = NULL;
  181. }

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

闽ICP备14008679号