当前位置:   article > 正文

单链表详解

单链表

目录

一、什么是链表

1、数据结构概要

2、功能

二、实现链表

1、定义一个具有结点特征的结构体

2、定义一个头指针

 3、实现尾插

尾插代码实现如下:

4、结点的创建:

 创建节点代码实现:

5、实现尾删

 尾删代码实现:

6、实现头插

头插代码实现:

 7、实现头删

头删代码实现:

8、实现任意结点位置的后的插入

任意插入代码实现:

9、实现任意结点位置后的删除

任意删除代码实现:

10、实现打印

打印代码实现:

11、实现查找某一数据的结点

查找代码实现:

12、实现某一位置结点数据的修改

修改数据代码实现:

三、全部代码附上

SList.h部分:

SList.c部分:

text.c部分:

运行结果附上:


一、什么是链表


1、数据结构概要


数据结构就是用某种结构去储存数据:

1、物理结构(数据在内存中的存储)

2、逻辑结构(由人为想象出来的)

顺序表就是逻辑和物理都连续的一种线性表。说明白一点顺序表就是玩数组。

链表就是逻辑连续,物理不一定连续的线性表。如下图,逻辑上是利用指针将其串联起来的,物理上却是杂乱的,最后以NULL空指针结束。




2、功能


大致了解什么是链表后,我们还需要知道链表的大概的功能有哪些? 

1、首先清楚它是用于储存数据的一种结构

2、尾部插入数据,尾部删除数据,头部插入数据,头部删除数据,任意位置的插入,任意位置的删除,查找数据位置,修改数据的功能。


二、实现链表


1、定义一个具有结点特征的结构体


因为结构体内储存的数据类型不是确定的,为了避免以后维护起来太麻烦,所幸将类型重定义一下。

在链表中这样的一个结构体类型称为一个结点,我们需要这个结点指向下一个结点,所以需要定义一个结点类型的指针。

  1. typedef int SListDateType;
  2. //结点
  3. typedef struct SListNode
  4. {
  5. SListDateType date;
  6. struct SListNode* Next;
  7. }SListNode;

2、定义一个头指针


这是最简单的单链表结构,相当于是一个空单链表

 

 3、实现尾插


实现尾插有两种情况:1、phead头指针为NULL。2、phead头指针为非空。

尾插代码实现如下:

  1. void SListPushBack(SListNode** pphead, SListDateType x)
  2. {
  3. //创建结点
  4. SListNode* newnode = BuySListNode(x);
  5. //第一种情况
  6. if (*pphead == NULL)
  7. {
  8. *pphead = newnode;
  9. }
  10. //第二种情况
  11. else
  12. {
  13. SListNode* tail = *pphead;
  14. while (tail->Next != NULL)
  15. {
  16. tail = tail->Next;
  17. }
  18. tail->Next = newnode;
  19. }
  20. }

4、结点的创建:


 创建节点代码实现:

  1. //创建一个结点
  2. static SListNode* BuySListNode(SListDateType x)
  3. {
  4. SListNode* NewNode = (SListNode*)malloc(sizeof(SListNode));
  5. if (NewNode == NULL)
  6. {
  7. printf("开辟空间失败\n");
  8. exit(-1);
  9. }
  10. NewNode->date = x;
  11. NewNode->Next = NULL;
  12. return NewNode;
  13. }

5、实现尾删


 实现尾删分三种情况:1、phead头指针为空指针。2、phead头指针不为空指针,只有一个结点。3、phead不为空指针、有多个结点。

 尾删代码实现:

  1. //尾删
  2. void SListPopBack(SListNode** pphead)
  3. {
  4. //如果是空链表
  5. if (*pphead == NULL)
  6. {
  7. return;
  8. }
  9. //如果只有一个结点
  10. else if ((*pphead)->Next == NULL)
  11. {
  12. free(*pphead);
  13. *pphead = NULL;
  14. }
  15. //如果有多个结点
  16. else
  17. {
  18. SListNode* prev = NULL;//前一个结点
  19. SListNode* tail = *pphead;//尾结点
  20. while (tail ->Next != NULL)
  21. {
  22. prev = tail;
  23. tail = tail->Next;
  24. }
  25. free(tail);
  26. tail = NULL;
  27. prev->Next = NULL;
  28. }
  29. }

6、实现头插


实现头插分两种情况:1、phead == NULL。2、phead != NULL。

 由图解分析:两种情况用代码实现其实是一种逻辑。

头插代码实现:

  1. //头插
  2. void SListPushFront(SListNode** pphead, SListDateType x)
  3. {
  4. //创建结点
  5. SListNode* newnode = BuySListNode(x);
  6. newnode->Next = *pphead;
  7. *pphead = newnode;
  8. }

 7、实现头删


实现头删有三种情况:1、phead == NULL。2、phead != NULL ,有一个结点。3、phead != NULL,有多个结点。

又图解分析,后面两种也可划分为一种代码实现逻辑:1、phead == NULL。2、phead != NULL,一个节点 + 多个结点的情况。

头删代码实现:

  1. //头删
  2. void SListPopFront(SListNode** pphead)
  3. {
  4. //1.phead == NULL
  5. //2.有一个结点 + 有多个结点
  6. if (*pphead == NULL)
  7. {
  8. return;
  9. }
  10. else
  11. {
  12. SListNode* cur = *pphead;
  13. *pphead = (*pphead)->Next;
  14. free(cur);
  15. cur = NULL;
  16. }
  17. }

8、实现任意结点位置的后的插入


因为单链表的缺陷(后一个结点无法找到前一个结点)所以只能实现结点后的插入,无法实现结点前的插入。

这种功能的实现也有三种情况:

如下图解分析:

 

 

图解分析:后只有一个结点 + 有多个结点)的代码逻辑相同 

任意插入代码实现:

  1. //任意插入
  2. void SListInsertAfter(SListNode** pphead, SListDateType pos, SListDateType x)
  3. {
  4. SListNode* newnode = BuySListNode(x);
  5. if (*pphead == NULL)
  6. {
  7. *pphead = newnode;
  8. }
  9. else
  10. {
  11. SListNode* cur = *pphead;
  12. while (cur->date != pos)
  13. {
  14. cur = cur->Next;
  15. }
  16. newnode->Next = cur->Next;//这里使用第二种避免找不到地址的方法
  17. cur->Next = newnode;
  18. }
  19. }

 

9、实现任意结点位置后的删除


实现删除:3种情况:1、phead == NULL。 2、phead != NULL,一个结点。 3、phead != NULL,多个结点。

 

 

 

 由图解分析:

任意删除代码实现:

  1. //任意结点后删除
  2. void SListEraseAfter(SListNode** pphead, SListDateType pos)
  3. {
  4. if (*pphead == NULL)
  5. {
  6. return;
  7. }
  8. else if ((*pphead)->Next == NULL)
  9. {
  10. free(*pphead);
  11. *pphead = NULL;
  12. }
  13. else
  14. {
  15. SListNode* cur = *pphead;
  16. while (cur->date != pos)
  17. {
  18. cur->Next;
  19. }
  20. SListNode* next = cur->Next;
  21. SListNode* nextnext = next->Next;
  22. free(next);
  23. next = NULL;
  24. cur->Next = nextnext;
  25. }
  26. }

10、实现打印

 

 

 由图解分析:三种情况下的开始。迭代,结束条件都是相同的,所以代码实现逻辑相同。

打印代码实现:

  1. //打印
  2. void SListPrint(SListNode* phead)
  3. {
  4. SListNode* Cur = phead;
  5. while (Cur != NULL)//遍历
  6. {
  7. printf("%d->", Cur->date);
  8. Cur = Cur->Next;
  9. }
  10. printf("NULL\n");
  11. }

11、实现查找某一数据的结点

查找代码实现:

  1. SListNode* SListFind(SListNode* phead, SListDateType x)
  2. {
  3. assert(phead);
  4. SListNode* cur = phead;
  5. while (cur)
  6. {
  7. if (cur->date == x)
  8. {
  9. return cur;
  10. }
  11. cur = cur->Next;
  12. }
  13. return NULL;
  14. }

 

12、实现某一位置结点数据的修改

修改其实可以说和查找差不多,一模一样,只是在找到后,在对其的数据行修改即可。

修改数据代码实现:

  1. //任意结点数据的修改
  2. void SListChange(SListNode* phead, SListDateType pos, SListDateType x)
  3. {
  4. SListNode* cur = phead;
  5. while (cur->date != pos)
  6. {
  7. cur = cur->Next;
  8. }
  9. cur->date = x;
  10. }

三、全部代码附上

SList.h部分:

  1. #pragma once
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <assert.h>
  5. typedef int SListDateType;
  6. //结点
  7. typedef struct SListNode
  8. {
  9. SListDateType date;
  10. struct SListNode* Next;
  11. }SListNode;
  12. //尾插
  13. void SListPushBack(SListNode** pphead, SListDateType x);
  14. //尾删
  15. void SListPopBack(SListNode** pphead);
  16. //头插
  17. void SListPushFront(SListNode** pphead, SListDateType x);
  18. //头删
  19. void SListPopFront(SListNode** pphead);
  20. //打印
  21. void SListPrint(SListNode* phead);
  22. //查找
  23. SListNode* SListFind(SListNode* phead, SListDateType x);
  24. //任意结点后的插入
  25. void SListInsertAfter(SListNode** pphead, SListDateType pos, SListDateType x);
  26. //任意结点后的删除
  27. void SListEraseAfter(SListNode** pphead, SListDateType pos);
  28. //任意位置的修改
  29. void SListChange(SListNode* phead, SListDateType pos, SListDateType x);

SList.c部分:

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "Slist.h"
  3. //创建一个结点
  4. static SListNode* BuySListNode(SListDateType x)
  5. {
  6. SListNode* NewNode = (SListNode*)malloc(sizeof(SListNode));
  7. if (NewNode == NULL)
  8. {
  9. printf("开辟空间失败\n");
  10. exit(-1);
  11. }
  12. NewNode->date = x;
  13. NewNode->Next = NULL;
  14. return NewNode;
  15. }
  16. //打印
  17. void SListPrint(SListNode* phead)
  18. {
  19. SListNode* Cur = phead;
  20. while (Cur != NULL)//遍历
  21. {
  22. printf("%d->", Cur->date);
  23. Cur = Cur->Next;
  24. }
  25. printf("NULL\n");
  26. }
  27. //尾插
  28. void SListPushBack(SListNode** pphead, SListDateType x)
  29. {
  30. //创建结点
  31. SListNode* newnode = BuySListNode(x);
  32. //第一种情况,phead == NULL
  33. if (*pphead == NULL)
  34. {
  35. *pphead = newnode;
  36. }
  37. //第二种情况,phead != NULL
  38. else
  39. {
  40. SListNode* tail = *pphead;
  41. while (tail->Next != NULL)
  42. {
  43. tail = tail->Next;
  44. }
  45. tail->Next = newnode;
  46. }
  47. }
  48. //尾删
  49. void SListPopBack(SListNode** pphead)
  50. {
  51. //如果是空链表
  52. if (*pphead == NULL)
  53. {
  54. return;
  55. }
  56. //如果只有一个结点
  57. else if ((*pphead)->Next == NULL)
  58. {
  59. free(*pphead);
  60. *pphead = NULL;
  61. }
  62. //如果有多个结点
  63. else
  64. {
  65. SListNode* prev = NULL;//前一个结点
  66. SListNode* tail = *pphead;//尾结点
  67. while (tail ->Next != NULL)
  68. {
  69. prev = tail;
  70. tail = tail->Next;
  71. }
  72. free(tail);
  73. tail = NULL;
  74. prev->Next = NULL;
  75. }
  76. }
  77. //头插
  78. void SListPushFront(SListNode** pphead, SListDateType x)
  79. {
  80. //创建结点
  81. SListNode* newnode = BuySListNode(x);
  82. newnode->Next = *pphead;
  83. *pphead = newnode;
  84. }
  85. //头删
  86. void SListPopFront(SListNode** pphead)
  87. {
  88. //1.phead == NULL
  89. //2.有一个结点 + 有多个结点
  90. if (*pphead == NULL)
  91. {
  92. return;
  93. }
  94. else
  95. {
  96. SListNode* cur = *pphead;
  97. *pphead = (*pphead)->Next;
  98. free(cur);
  99. cur = NULL;
  100. }
  101. }
  102. //查找
  103. SListNode* SListFind(SListNode* phead, SListDateType x)
  104. {
  105. assert(phead);
  106. SListNode* cur = phead;
  107. while (cur)
  108. {
  109. if (cur->date == x)
  110. {
  111. return cur;
  112. }
  113. cur = cur->Next;
  114. }
  115. return NULL;
  116. }
  117. //任意插入
  118. void SListInsertAfter(SListNode** pphead, SListDateType pos, SListDateType x)
  119. {
  120. SListNode* newnode = BuySListNode(x);
  121. if (*pphead == NULL)
  122. {
  123. *pphead = newnode;
  124. }
  125. else
  126. {
  127. SListNode* cur = *pphead;
  128. while (cur->date != pos)
  129. {
  130. cur = cur->Next;
  131. }
  132. newnode->Next = cur->Next;
  133. cur->Next = newnode;
  134. }
  135. }
  136. //任意结点后删除
  137. void SListEraseAfter(SListNode** pphead, SListDateType pos)
  138. {
  139. if (*pphead == NULL)
  140. {
  141. return;
  142. }
  143. else if ((*pphead)->Next == NULL)
  144. {
  145. free(*pphead);
  146. *pphead = NULL;
  147. }
  148. else
  149. {
  150. SListNode* cur = *pphead;
  151. while (cur->date != pos)
  152. {
  153. cur->Next;
  154. }
  155. SListNode* next = cur->Next;
  156. SListNode* nextnext = next->Next;
  157. free(next);
  158. next = NULL;
  159. cur->Next = nextnext;
  160. }
  161. }
  162. //任意结点数据的修改
  163. void SListChange(SListNode* phead, SListDateType pos, SListDateType x)
  164. {
  165. SListNode* cur = phead;
  166. while (cur->date != pos)
  167. {
  168. cur = cur->Next;
  169. }
  170. cur->date = x;
  171. }

text.c部分:

  1. #define _CRT_SECURE_NO_WARNINGS 1
  2. #include "Slist.h"
  3. void TextSList(SListNode* phead)
  4. {
  5. SListPushBack(&phead, 1);
  6. SListPushBack(&phead, 2);
  7. SListPushBack(&phead, 3);
  8. SListPrint(phead);
  9. SListPushFront(&phead, 22);
  10. SListPrint(phead);
  11. SListPopFront(&phead);
  12. SListPrint(phead);
  13. }
  14. void TextSListFind(SListNode* phead)
  15. {
  16. SListPushBack(&phead, 1);
  17. SListPushBack(&phead, 2);
  18. SListPushBack(&phead, 3);
  19. SListPrint(phead);
  20. SListPushFront(&phead, 22);
  21. SListPrint(phead);
  22. SListPopFront(&phead);
  23. SListPrint(phead);
  24. SListNode* ret = SListFind(phead, 3);
  25. if (ret != NULL)
  26. {
  27. ret->date = 100;
  28. }
  29. SListPrint(phead);
  30. SListChange(phead, 1, 1000);
  31. SListPrint(phead);
  32. SListEraseAfter(&phead, 1000);
  33. SListPrint(phead);
  34. SListInsertAfter(&phead, 1000, 2);
  35. SListPrint(phead);
  36. CSList(&phead);
  37. SListPrint(phead);
  38. }
  39. int main()
  40. {
  41. //头指针:最简单的单链表
  42. //SListNode* pList = NULL;
  43. SListNode* phead = NULL;
  44. //TextSList(phead);
  45. TextSListFind(phead);
  46. return 0;
  47. }

运行结果附上:

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

闽ICP备14008679号