当前位置:   article > 正文

数据结构之链表实现(c语言)_c语言链表实现

c语言链表实现

在数据结构的线性表中有:顺序表,链表等等。

动态顺序表是利用malloc函数创造出一段连续的空间,通过下标来访问空间中的每一个成员。

而今天介绍的链表与顺序表有很大的不同,链表是每有一个新的变量产生就会去malloc一个存放该变量的空间。并且是通过指针相连接。

链表有很多种:

1,单向链表:顾名思义他是只能朝一个方向走的。

1.1.1 单向带头链表 1.1.2 单向不带头链表。

在这里的头也可以叫做哨兵位,他里面存的数据我们是不关心的。我们只是用他来记住链表的头而已。

我们可以从图中看出单向链表之所以 单向是因为他的尾节点指针为空。

2,双向链表

双向链表,每个元素直接可以互相访问。

3,循环链表

循环链表就是尾节点可以指向头节点的链表。

单向,双向,带头,循环。以上几种特性可以随机结合,生成一种链表。链表种类有很多,这次要着重介绍的就是单向不循环不带头链表。

首先创建一个结构体用来存放数据和指向下一块空间的指针。

  1. typedef int Datatype;
  2. //创建一个结构体来存放数据以及指向下一个数据的指针
  3. typedef struct singlelinklist
  4. {
  5. int data;
  6. struct singlelinklist* next;
  7. }SLList;

 1、创建数据

先将要存入数据传入函数,将next指针置空,返回创建好的空间。

  1. SLList* buydata(Datatype n)
  2. {
  3. SLList* newnode = (SLList*)malloc(sizeof(SLList));
  4. if(newnode == NULL)
  5. {
  6. perror("malloc fail");
  7. exit(-1);
  8. }
  9. newnode->data = n;
  10. newnode->next = NULL;
  11. return newnode;
  12. }

2、连接数据

用第一块的next指向下一块空间即可。因为单向的原因,我们需要再创建两个指针。一个叫head

一个叫tail。我们将head放在链表的第一个节点让他做头节点,tail作尾节点,放在链表的最后一个节点。每创建一个节点就将tail的next节点放在新节点上,再更新tail。最后返回头节点。

  1. SLList* Creatsinglinklist(Datatype n)
  2. {
  3. SLList* head = NULL, * tail = NULL;
  4. for(int i = 0;i<n;i++)
  5. {
  6. SLList* newnode = buydata(i);
  7. if(head == NULL)
  8. {
  9. head = tail = newnode;
  10. }
  11. else
  12. {
  13. tail->next = newnode;
  14. tail = newnode;
  15. }
  16. }
  17. return head;
  18. }

3、尾删

链表的尾删就是将链表的最后一个节点删除。在实现这个功能时,我们应该考虑链表中的节点个数,当只有一个节点时。我们直接将该节点free掉,在将他置空。但是如果使用一级指针的话,由于形参的改变无法改变实参,所以在这里我们应该传入的是头节点的地址。在参数设置时也应该特别注意。另外,在释放掉尾节点时,新的尾节点的next应该指向空。

  1. void Tail_deletion(SLList** sl)
  2. {
  3. if((*sl)->next == NULL)
  4. {
  5. free(*sl);
  6. *sl = NULL;
  7. }
  8. else
  9. {
  10. SLList* prev = NULL;
  11. SLList* tail = *sl;
  12. while (tail->next)
  13. {
  14. prev = tail;
  15. tail = tail->next;
  16. }
  17. prev->next = NULL;
  18. free(tail);
  19. }
  20. }

4、尾插

在尾插元素时,我们也应该考虑到有可能该链表为空的情况,因此在参数设置时依旧使用二级指针传参。在该函数编写时我们先找到尾部,再进行操作。最后将新的尾节点的next置空。

  1. void Tail_plugs(SLList** sl, Datatype n)
  2. {
  3. SLList* newnode = buydata(n);
  4. SLList* newtail = *sl;
  5. if(*sl == NULL)
  6. {
  7. *sl = newnode;
  8. }
  9. else
  10. {
  11. //
  12. while(newtail->next)
  13. {
  14. newtail = newtail->next;
  15. }
  16. newtail->next = newnode;
  17. }
  18. }

5、打印

我们先在函数中定义一个尾节点,尾节点开始时指向头节点,利用循环依次打印出数据即可。

  1. void print(SLList* sl)
  2. {
  3. assert(sl);
  4. SLList* tail = sl;
  5. while(tail)
  6. {
  7. printf("%d->", tail->data);
  8. tail = tail->next;
  9. }
  10. printf("NULL\n");
  11. }

6、头插

头插时依然要想到,如果链表中没有节点的情况并且我们需要更新头节点。然后我们创建一个新的节点指向原先的头部即可。最后返回新的头部。

  1. void Head_plug(SLList** sl, Datatype n)
  2. {
  3. SLList* newnode = buydata(n);
  4. if(*sl = NULL)
  5. {
  6. *sl = newnode;
  7. }
  8. else
  9. {
  10. newnode->next = *sl;
  11. }
  12. *sl = newnode;
  13. }

7、头删

因为我们需要改变头节点的地址,所以还是需要二级指针。当链表为空是直接返回空即可。

  1. SLList* Head_deletion(SLList** sl)
  2. {
  3. SLList* newhead = *sl;
  4. SLList* prev = *sl;
  5. if(*sl == NULL)
  6. {
  7. return;
  8. }
  9. else
  10. {
  11. newhead = (*sl)->next;
  12. free(*sl);
  13. }
  14. return newhead;
  15. }

8、查找元素位置

在这个函数中我们需要返回查找到的元素的地址,并不需要对参数进行操作。在这里我们只需要遍历链表,在遍历的过程中进行比较。如果相等返回地址即可。

  1. SLList* Linked_list_lookup(SLList* pos, Datatype n)
  2. {
  3. assert(pos);
  4. SLList* tail = pos;
  5. while(tail)
  6. {
  7. if(tail->data == n)
  8. {
  9. return tail;
  10. }
  11. tail = tail->next;
  12. }
  13. return NULL;
  14. }

9、在pos位置之后的数据插入

我们直接将pos的next保存下来,在将pos的next指向新元素。将这三个节点连接起来即可。

  1. void Insert_backwards(SLList* pos, Datatype n)
  2. {
  3. SLList* newnode = buydata(n);
  4. SLList* tail = pos->next;
  5. pos->next = newnode;
  6. newnode->next = tail;
  7. }

10、删除pos之后的位置

因为我们删除的是pos之后的位置,首先应该判断pos的next是否为空,因为我们的pos很有可能是链表的尾。在判断之后,将pos给pos的next的next即可。在这里我们可以在定义一个指针来存放pos的next的地址。

  1. void Delete_backwards(SLList* pos)
  2. {
  3. if(pos->next = NULL)
  4. {
  5. return;
  6. }
  7. else
  8. {
  9. SLList* node = pos->next;
  10. pos->next = node->next;
  11. free(node);
  12. }
  13. }

11、在pos位之前的插入

首先判断pos是否是链表的头节点,如果是函数逻辑写为头插,如果不是,我们依然需要定义指针,一个指向pos的next,另一个先指向头节点,通过迭代使指针指向pos的前一个节点。

  1. void Insert_forward(SLList** phead,SLList* pos,Datatype n)
  2. {
  3. SLList* newnode = buydata(n);
  4. if(*phead == pos)
  5. {
  6. Head_plug(phead, n);
  7. }
  8. else
  9. {
  10. SLList* prev = *phead;
  11. while(prev->next != pos )
  12. {
  13. prev = prev->next;
  14. }
  15. SLList* node = prev;
  16. node->next = newnode;
  17. newnode->next = pos;
  18. }
  19. }

12、删除pos位

当pos位为头节点时,我们会改变头节点的地址,所以我们在这里的phead需要传入地址,并且在最后也应该将phead的新地址返回。但pos不是头节点时,我们创建一个指针先指向phead通过迭代时指针指向pos位的前一个节点。

  1. void deleted_pos(SLList** phead, SLList* pos)
  2. {
  3. if(*phead == pos)
  4. {
  5. Head_deletion(phead);
  6. }
  7. else
  8. {
  9. SLList* prev = *phead;
  10. while(prev->next != pos)
  11. {
  12. prev = prev->next;
  13. }
  14. prev->next = pos->next;
  15. free(pos);
  16. }
  17. }

13、销毁链表

在这里我们需要将phead的空间free掉,地址置空。但传入一级指针是没有办法将传入phead的地址给置空的。因此依旧传入二级指针。通过迭代依次释放空间,最后置空即可。

  1. void Destroyed(SLList** sl)
  2. {
  3. SLList* cur = *sl;
  4. while(cur)
  5. {
  6. SLList* node = cur->next;
  7. free(cur);
  8. cur = node;
  9. }
  10. *sl = NULL;
  11. }

完整版代码:

头文件:

  1. #pragma once
  2. #include<stdio.h>
  3. #include<assert.h>
  4. #include<stdlib.h>
  5. typedef int Datatype;
  6. //创建一个结构体来存放数据以及指向下一个数据的指针
  7. typedef struct singlelinklist
  8. {
  9. int data;
  10. struct singlelinklist* next;
  11. }SLList;
  12. //接口实现:增删查改
  13. //创建一个数据
  14. SLList* buydata(Datatype n);
  15. //将创造的各项数据通过指针连接起来
  16. SLList* Creatsinglinklist(Datatype n);
  17. //打印链表中的数据
  18. void print(SLList* sl);
  19. //尾删
  20. void Tail_deletion(SLList** sl);
  21. //尾插
  22. void Tail_plugs(SLList** sl, Datatype n);
  23. //头插
  24. void Head_plug(SLList** sl, Datatype n);
  25. //头删
  26. SLList* Head_deletion(SLList** sl);
  27. //查找
  28. SLList* Linked_list_lookup(SLList* pos, Datatype n);
  29. //在pos位之后的插入
  30. void Insert_backwards(SLList* pos, Datatype n);
  31. //在pos位之后的删除
  32. void Delete_backwards(SLList* pos);
  33. //在pos位之前的插入
  34. void Insert_forward(SLList** phead, SLList* pos, Datatype n);
  35. //删除pos位
  36. void deleted_pos(SLList** phead, SLList* pos);
  37. //销毁
  38. void Destroyed(SLList** sl);

接口实现:

  1. #include "singlelinklist.h"
  2. SLList* buydata(Datatype n)
  3. {
  4. SLList* newnode = (SLList*)malloc(sizeof(SLList));
  5. if(newnode == NULL)
  6. {
  7. perror("malloc fail");
  8. exit(-1);
  9. }
  10. newnode->data = n;
  11. newnode->next = NULL;
  12. return newnode;
  13. }
  14. SLList* Creatsinglinklist(Datatype n)
  15. {
  16. SLList* head = NULL, * tail = NULL;
  17. for(int i = 0;i<n;i++)
  18. {
  19. SLList* newnode = buydata(i);
  20. if(head == NULL)
  21. {
  22. head = tail = newnode;
  23. }
  24. else
  25. {
  26. tail->next = newnode;
  27. tail = newnode;
  28. }
  29. }
  30. return head;
  31. }
  32. void print(SLList* sl)
  33. {
  34. assert(sl);
  35. SLList* tail = sl;
  36. while(tail)
  37. {
  38. printf("%d->", tail->data);
  39. tail = tail->next;
  40. }
  41. printf("NULL\n");
  42. }
  43. void Tail_deletion(SLList** sl)
  44. {
  45. if((*sl)->next == NULL)
  46. {
  47. free(*sl);
  48. *sl = NULL;
  49. }
  50. else
  51. {
  52. SLList* prev = NULL;
  53. SLList* tail = *sl;
  54. while (tail->next)
  55. {
  56. prev = tail;
  57. tail = tail->next;
  58. }
  59. prev->next = NULL;
  60. free(tail);
  61. }
  62. }
  63. void Tail_plugs(SLList** sl, Datatype n)
  64. {
  65. SLList* newnode = buydata(n);
  66. SLList* newtail = *sl;
  67. if(*sl == NULL)
  68. {
  69. *sl = newnode;
  70. }
  71. else
  72. {
  73. //β
  74. while(newtail->next)
  75. {
  76. newtail = newtail->next;
  77. }
  78. newtail->next = newnode;
  79. }
  80. }
  81. void Head_plug(SLList** sl, Datatype n)
  82. {
  83. SLList* newnode = buydata(n);
  84. if(*sl = NULL)
  85. {
  86. *sl = newnode;
  87. }
  88. else
  89. {
  90. newnode->next = *sl;
  91. }
  92. *sl = newnode;
  93. }
  94. SLList* Head_deletion(SLList** sl)
  95. {
  96. SLList* newhead = *sl;
  97. SLList* prev = *sl;
  98. if(*sl == NULL)
  99. {
  100. return;
  101. }
  102. else
  103. {
  104. newhead = (*sl)->next;
  105. free(*sl);
  106. }
  107. return newhead;
  108. }
  109. SLList* Linked_list_lookup(SLList* pos, Datatype n)
  110. {
  111. assert(pos);
  112. SLList* tail = pos;
  113. while(tail)
  114. {
  115. if(tail->data == n)
  116. {
  117. return tail;
  118. }
  119. tail = tail->next;
  120. }
  121. return NULL;
  122. }
  123. void Insert_backwards(SLList* pos, Datatype n)
  124. {
  125. SLList* newnode = buydata(n);
  126. SLList* tail = pos->next;
  127. pos->next = newnode;
  128. newnode->next = tail;
  129. }
  130. void Delete_backwards(SLList* pos)
  131. {
  132. if(pos->next = NULL)
  133. {
  134. return;
  135. }
  136. else
  137. {
  138. SLList* node = pos->next;
  139. pos->next = node->next;
  140. free(node);
  141. }
  142. }
  143. void Insert_forward(SLList** phead,SLList* pos,Datatype n)
  144. {
  145. SLList* newnode = buydata(n);
  146. if(*phead == pos)
  147. {
  148. Head_plug(phead, n);
  149. }
  150. else
  151. {
  152. SLList* prev = *phead;
  153. while(prev->next != pos )
  154. {
  155. prev = prev->next;
  156. }
  157. SLList* node = prev;
  158. node->next = newnode;
  159. newnode->next = pos;
  160. }
  161. }
  162. void deleted_pos(SLList** phead, SLList* pos)
  163. {
  164. if(*phead == pos)
  165. {
  166. Head_deletion(phead);
  167. }
  168. else
  169. {
  170. SLList* prev = *phead;
  171. while(prev->next != pos)
  172. {
  173. prev = prev->next;
  174. }
  175. prev->next = pos->next;
  176. free(pos);
  177. }
  178. }
  179. void Destroyed(SLList** sl)
  180. {
  181. SLList* cur = *sl;
  182. while(cur)
  183. {
  184. SLList* node = cur->next;
  185. free(cur);
  186. cur = node;
  187. }
  188. *sl = NULL;
  189. }

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号