• 数据结构之单链表


    一. 单链表定义(single linked list)

    概念:链表是一种物理存储结构非连续、非顺序存储结构,但链表在逻辑上连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

    所谓单链表就是:单向链表,我们将链表中的每个元素称之为结点/节点单链表中的每个节点是单向的,也就是说,我们无法直接获得某一结点的前面的第一个结点,即:前驱结点。

    二. 结构

    链表是由一个个结点组成的

    单链表是一种常见的数据结构,用于存储和操作一系列的数据。它由节点组成,每个节点包含数据和指向下一个节点的指针。

    三. 链表的实现

    1> 定义结点

    1. typedef int SLTDateType;
    2. typedef struct SListNode
    3. {
    4. SLTDateType Date;
    5. SListNode* next;
    6. }SListNode;

    2> 链表功能

    1. //创建一个结点
    2. SLTNode* BuyListNode(SLTDateType x);
    3. //销毁单链表
    4. void SLTDestory(SLTNode** pphead);
    5. //单链表头插
    6. void SLTPushFront(SLTNode** pphead, SLTDateType x);
    7. //单链表尾插
    8. void SLTPushBack(SLTNode** pphead, SLTDateType x);
    9. //单链表头删
    10. void SLTPopFront(SLTNode** pphead);
    11. //单链表尾删
    12. void SLTPopBack(SLTNode** pphead);
    13. //单链表结点查找
    14. SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x);
    15. //单链表结点删除(删除pos位置的结点)
    16. void SLTErase(SLTNode** pphead, SLTNode* pos);
    17. //单链表结点插入(在pos之前插入)
    18. void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x);
    19. // 单链表结点插入(在pos之后插入)
    20. void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x);
    21. // 单链表结点修改
    22. void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x);
    23. //打印单链表
    24. void PrintSLT(SLTNode * phead);

    3> 链表功能的实现 

    1. #include"SLT.h"
    2. //建立一个新的结点
    3. //这是链表的缺点:经常需要使用malloc为newnode开辟空间
    4. SLTNode* BuyListNode(SLTDateType x)
    5. {
    6. //为什么要用malloc,是因为,如果在BuyListNode函数中SLTNode newnode,出了这个函数,newnode就被销毁了,
    7. //用malloc开辟空间,只要我们不主动释放这个空间,这个空间的数据一直存在,
    8. SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
    9. //static SLTNode newnode;
    10. if (newnode == NULL)
    11. {
    12. perror("malloc:");
    13. exit(0);
    14. }
    15. newnode->data = x;
    16. newnode->next = NULL;
    17. return newnode;
    18. }
    19. //头插
    20. void SLTPushFront(SLTNode** pphead, SLTDateType x)
    21. {
    22. assert(pphead);//phead可能为NULL,但是pphead指向phead,不可能为空
    23. SLTNode* newnode = BuyListNode(x);
    24. //这里可不是newnode->next = (*pphead)->next;
    25. newnode->next = *pphead;
    26. *pphead = newnode;
    27. }
    28. //尾插
    29. //尾插特别容易出错,当链表中没有数据,即phead=NULL时,尾插就相当于头插了,此时需要改变phead的值
    30. void SLTPushBack(SLTNode** pphead, SLTDateType x)
    31. {
    32. assert(pphead);
    33. SLTNode* newnode = BuyListNode(x);
    34. //1、空
    35. //2、非空
    36. if (*pphead == NULL)
    37. {
    38. *pphead = newnode;
    39. //newnode->next = NULL;这一步是不需要的,newnode在建立的时候就默认newnode->next=NULL
    40. }
    41. else
    42. {
    43. SLTNode* cur = *pphead;
    44. //这是单向链表的缺点,需要去找尾
    45. while (cur->next != NULL)
    46. {
    47. cur = cur->next;
    48. }
    49. cur->next = newnode;
    50. }
    51. }
    52. //头删
    53. void SLTPopFront(SLTNode** pphead)
    54. {
    55. assert(pphead);
    56. //温柔的检查
    57. if (*pphead == NULL)
    58. return;
    59. //暴力的检查
    60. assert(*pphead);
    61. SLTNode* head = *pphead;
    62. *pphead = (*pphead)->next;
    63. free(head);
    64. head = NULL;
    65. }
    66. //尾删
    67. void SLTPopBack(SLTNode** pphead)
    68. {
    69. assert(pphead);
    70. assert(*pphead);
    71. //1、一个结点
    72. //2、两个结点
    73. if ((*pphead)->next == NULL)
    74. {
    75. free(*pphead);
    76. *pphead = NULL;
    77. }
    78. else
    79. {
    80. SLTNode* cur = *pphead;
    81. while (cur->next->next)
    82. {
    83. cur = cur->next;
    84. }
    85. free(cur->next);
    86. cur->next = NULL;
    87. }
    88. }
    89. //打印单向链表
    90. void PrintSLT(SLTNode* phead)
    91. {
    92. SLTNode* cur = phead;
    93. while (cur != NULL)
    94. {
    95. printf("%d->", cur->data);
    96. cur = cur->next;
    97. }
    98. printf("NULL");
    99. printf("\n");
    100. }
    101. //单链表查找某个结点
    102. SLTNode* SLTNodeFind(SLTNode* phead, SLTDateType x)
    103. {
    104. SLTNode* find = phead;
    105. //别忘记分析找不到结点的情况
    106. while (find)
    107. {
    108. if (find->data == x)
    109. {
    110. return find;
    111. }
    112. find = find->next;
    113. }
    114. return NULL;
    115. }
    116. //删除pos位置的结点
    117. void SLTErase(SLTNode** pphead, SLTNode* pos)
    118. {
    119. assert(pphead);
    120. assert(pos);
    121. if (pos == *pphead)
    122. {
    123. SLTPopFront(pphead);
    124. }
    125. else
    126. {
    127. SLTNode* prev = *pphead;
    128. while (prev->next != pos)
    129. {
    130. prev = prev->next;
    131. //如果prev->next已经为空了,说明链表已经查完了,还没有查到pos
    132. //证明pos传入有误
    133. assert(prev->next);
    134. }
    135. prev->next = pos->next;
    136. free(pos);
    137. //pos = NULL;这个没必要,改变不了pos
    138. }
    139. }
    140. //单链表结点前插
    141. //一般插入结点都是在pos之前插入,但单链表在实现前插是比较困难的
    142. void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDateType x)
    143. {
    144. assert(pphead);
    145. //头插
    146. if (pos == *pphead)
    147. {
    148. SLTPushFront(pphead, x);
    149. }
    150. //非头插
    151. else
    152. {
    153. SLTNode* prev = *pphead;
    154. while (prev->next != pos)
    155. {
    156. prev = prev->next;
    157. assert(prev->next);
    158. }
    159. SLTNode* newnode = BuyListNode(x);
    160. prev->next = newnode;
    161. newnode->next = pos;
    162. }
    163. }
    164. //单链表结点后插
    165. void SLTInsertBack(SLTNode** pphead, SLTNode* pos, SLTDateType x)
    166. {
    167. SLTNode* cur = *pphead;
    168. while (cur != pos)
    169. {
    170. cur = cur->next;
    171. //防止pos传错了
    172. assert(cur);
    173. }
    174. SLTNode* newnode = BuyListNode(x);
    175. newnode->next = pos->next;
    176. pos->next = newnode;
    177. }
    178. // 单链表结点修改
    179. void SLTModify(SLTNode* phead, SLTNode* pos, SLTDateType x)
    180. {
    181. SLTNode* cur = phead;
    182. while (cur != pos)
    183. {
    184. cur = cur->next;
    185. assert(cur);
    186. }
    187. pos->data = x;
    188. }
    189. //销毁链表
    190. void SLTDestory(SLTNode** pphead)
    191. {
    192. assert(pphead);
    193. SLTNode* cur = *pphead;
    194. //比cur->next!=NULL更好一些
    195. while (cur)
    196. {
    197. SLTNode* next = cur->next;
    198. free(cur);
    199. cur = next;
    200. }
    201. *pphead = NULL;
    202. }

    更加详细的请看原文【数据结构】——单链表超详细介绍(独家介绍,小白必看!!!)-CSDN博客 


    ❤️❤️❤️

  • 相关阅读:
    Java-1101
    如何做好商品的库存管理?哪些指标是衡量库存的指标
    近地面无人机植被定量遥感与生理参数反演
    c语言结构体数组
    React hooks(一):useState
    Codeforces Round #811 (Div. 3)补题(A-G)
    JS逆向爬虫案例分享(RSA非对称加密)
    Redis6.2.1版本集群新加副本
    Cent OS 使用ip addr or nmcli 分配临时IP地址
    数据集学习笔记(六):目标检测和图像分割标注软件介绍和使用,并转换成YOLO系列可使用的数据集格式
  • 原文地址:https://blog.csdn.net/qq_73340809/article/details/141093286