C语言中数据结构——单链表

简介: 🐰单链表🏡单链表的定义🏡单链表的打印🏡单链表的创建节点🏡单链表的头插🏡单链表的尾插🏡单链表的尾删🏡单链表的头删🏡单链表的查找🏡单链表的改动🏡单链表的元素个数🏡单链表的任意位置插入元素单链表的任意位置删除元素🏡单链表的销毁🏡单链表中的源码🌸main文件🌸头文件test.h🌸test.c文件

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

🐰单链表

🏡单链表的定义

🏡单链表的打印

🏡单链表的创建节点

🏡单链表的头插

🏡单链表的尾插

🏡单链表的尾删

🏡单链表的头删

🏡单链表的查找

🏡单链表的改动

🏡单链表的元素个数

🏡单链表的任意位置插入元素

单链表的任意位置删除元素

🏡单链表的销毁

🏡单链表中的源码

🌸main文件

🌸头文件test.h

🌸test.c文件


🐰单链表

🏡单链表的定义

1. typedef int SLTDataType;
2. typedef struct SListNode
3. {
4.     SLTDataType data;
5. struct SListNode* next;//next存放的下一个节点的地址
6. }SLT;

🏡单链表的打印

依次打印链表中的数据

1. void SLTprintf(SLT* phead)
2. {
3.     SLT* cur=phead;
4. while(cur!=NULL)
5.     {
6. printf("%d ",cur->data);
7.         cur=cur->next;
8.     }
9. printf("\n");
10. }

🏡单链表的创建节点

动态开辟一个空间,然后返回这个空间的地址,即动态开辟的节点

1. SLT* Buylistnode(int x)
2. {
3.     SLT* newnode=(SLT*)malloc(sizeof(SLT));
4. if(newnode==NULL)
5.     {
6. perror("malloc fail");
7. return 0;
8.     }
9.     newnode->data=x;
10.     newnode->next=NULL;
11. return newnode;
12. }

🏡单链表的头插

复用了动态创建节点

1. void SLTPushFront(SLT** pphead,SLTDataType x)
2. {
3.     SLT* newnode= Buylistnode(x);
4.     newnode->next=*pphead;
5.     *pphead=newnode;
6. }

🏡单链表的尾插

注意一个节点和多个节点时

1. void SLTPushBack(SLT** pphead,SLTDataType x)
2. {
3.     SLT* newnode=Buylistnode(x);
4. if(*pphead==NULL)//当为空链表时
5.     {
6.         *pphead=newnode;
7.     }
8. else
9.     {
10.         SLT* tail=*pphead;
11. while(tail->next)
12.         {
13.             tail=tail->next;
14.         }
15.         tail->next=newnode;
16.     }
17. }

🏡单链表的尾删

这两种方法的本质都是找到倒数第二个节点

第一种尾删的方法

注意一个节点和多个节点时

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

第二种尾删的方法

注意一个节点和多个节点时

1. void SLTPopBack(SLT** pphead)
2. {
3. assert(*pphead);
4.     SLT* tail=*pphead;
5. if(tail->next==NULL)//只有一个节点
6.     {
7. free(tail);
8.         *pphead=NULL;
9.     }
10. else//有多个节点
11.     {
12. while(tail->next->next)//这也是找到倒数第二个节点
13.         {
14.             tail=tail->next;
15.         }
16. free(tail->next);
17.         tail->next=NULL;
18.     }
19. }

🏡单链表的头删

注意一个节点和多个节点时

1. void SLTPopFront(SLT** pphead)
2. {
3. assert(*pphead);
4.     SLT* tail=*pphead;
5. if(tail->next==NULL)//一个节点
6.     {
7. free(tail);
8.         *pphead=NULL;
9.     }
10. else//多个节点
11.     {
12.         tail=tail->next;
13. free(*pphead);
14.         *pphead=tail;
15.     }
16. }

🏡单链表的查找

(找到了,就返回所在的位置,没找到返回-1)

1. int SLTFind(SLT** pphead,SLTDataType x)
2. {
3. assert(*pphead);
4.     SLT* try_b=*pphead;
5. int Count=1;
6. while(try_b->next)
7.     {
8. if(try_b->data==x)
9.         {
10. return Count;
11.         }
12.         Count++;
13.         try_b=try_b->next;
14.     }
15. return  -1;
16. }

🏡单链表的改动

需要给出改动的位置以及要改动的值

1. void SLTChange(SLT** pphead,int pos,SLTDataType x)
2. {
3. assert(*pphead);
4. int Count=Totalsize(pphead);
5. assert(pos<=Count);
6.     SLT* tail=*pphead;
7. while(pos--)
8.     {
9.         tail=tail->next;
10.     }
11.     tail->data=x;
12. }

🏡单链表的元素个数

计算链表的元素个数,然后返回个数

1. int Totalsize(SLT** pphead)
2. {
3.     SLT* tail=*pphead;
4. int Count=0;
5. while(tail)
6.     {
7.         tail=tail->next;
8.         Count++;
9.     }
10. return Count;
11. }

🏡单链表的任意位置插入元素

需要给出插入的位置以及要插入的值(说明一下,这里是插入元素的位置的后面),插入的位置一定要合法

1. void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x)
2. {
3. assert(pos<=Count);
4. if((*pphead)==NULL)
5.     {
6. SLTPushFront(pphead, x);
7.     }
8. else
9.     {
10.         SLT* prev=NULL;
11.         SLT* tail=*pphead;
12. while(pos--)
13.         {
14.             prev=tail;
15.             tail=tail->next;
16.         }
17.         SLT* newnode=Buylistnode(x);
18.         prev->next=newnode;
19.         newnode->next=tail;
20.     }
21. }

单链表的任意位置删除元素

删除的位置一定要合法

1. void SLTEraseAfter(SLT** pphead,int pos)
2. {
3. assert(*pphead);
4. assert(pos<=Count-1);
5. if((*pphead)->next==NULL)
6.    {
7. SLTPopFront(pphead);
8.    }
9. else
10.     {
11.         SLT* prev=NULL;
12.         SLT* taillater=NULL;
13.         SLT* tail=*pphead;
14. while(pos--)
15.         {
16.             prev=tail;
17.             tail=tail->next;
18.         }
19.         taillater=tail->next;
20. free(tail);
21.         tail=NULL;
22.         prev->next=taillater;
23.     }
24. }

🏡单链表的销毁

1. void SLTDestroy(SLT** pphead)
2. {
3. free(*pphead);
4.     *pphead=NULL;
5. }

🏡单链表中的源码

为方便调试单链表,这里没有使用了菜单

🌸main文件

1. #include"test.h"
2. void test1(void)
3. {
4.     SLT* plist=NULL;
5. SLTPushFront(&plist, 1);
6. SLTPushFront(&plist, 2);
7. SLTPushFront(&plist, 3);
8. SLTPushFront(&plist, 4);
9. SLTprintf(plist);
10. printf("\n");
11. SLTPushBack(&plist, 4);
12. SLTPushBack(&plist, 3);
13. SLTPushBack(&plist, 2);
14. SLTPushBack(&plist, 1);
15. SLTprintf(plist);
16. }
17. void test2(void)
18. {
19.     SLT* plist=NULL;
20. SLTPushFront(&plist, 1);
21. SLTPushFront(&plist, 2);
22. SLTPushFront(&plist, 3);
23. SLTPushFront(&plist, 4);
24. SLTPushBack(&plist, 4);
25. SLTPushBack(&plist, 3);
26. SLTPushBack(&plist, 2);
27. SLTPushBack(&plist, 1);
28. SLTprintf(plist);
29. //    SLTPopBack(&plist);
30. //    SLTPopBack(&plist);
31. //    SLTPopBack(&plist);
32. //    SLTPopBack(&plist);
33. //    SLTPopBack(&plist);
34. //    SLTPopBack(&plist);
35. //    SLTPopBack(&plist);
36. //    SLTprintf(plist);
37. SLTPopFront(&plist);
38. SLTPopFront(&plist);
39. SLTPopFront(&plist);
40. SLTPopFront(&plist);
41. SLTPopFront(&plist);
42. SLTPopFront(&plist);
43. SLTPopFront(&plist);
44. SLTPopFront(&plist);
45. SLTprintf(plist);
46. }
47. void test3(void)
48. {
49.     SLT* plist=NULL;
50. SLTPushFront(&plist, 1);
51. SLTPushFront(&plist, 2);
52. SLTPushFront(&plist, 3);
53. SLTPushFront(&plist, 4);
54. SLTPushBack(&plist, 4);
55. SLTPushBack(&plist, 3);
56. SLTPushBack(&plist, 2);
57. SLTPushBack(&plist, 1);
58. SLTprintf(plist);
59. int ret=SLTFind(&plist,4);
60. printf("position is('-1'is not find):%d\n",ret);
61. }
62. void test4(void)
63. {
64.     SLT* plist=NULL;
65. SLTPushFront(&plist, 1);
66. SLTPushFront(&plist, 2);
67. SLTPushFront(&plist, 3);
68. SLTPushFront(&plist, 4);
69. SLTPushBack(&plist, 4);
70. SLTPushBack(&plist, 3);
71. SLTPushBack(&plist, 2);
72. SLTPushBack(&plist, 1);
73. SLTprintf(plist);
74. SLTChange(&plist, 23, 100);
75. SLTprintf(plist);
76. }
77. void test5(void)
78. {
79.     SLT* plist=NULL;
80. SLTPushFront(&plist, 1);
81. SLTPushFront(&plist, 2);
82. SLTPushFront(&plist, 3);
83. SLTPushFront(&plist, 4);
84. SLTPushBack(&plist, 4);
85. SLTPushBack(&plist, 3);
86. SLTPushBack(&plist, 2);
87. SLTPushBack(&plist, 1);
88. SLTprintf(plist);
89. int ret=Totalsize(&plist);
90. SLTPopFront(&plist);
91. SLTPopFront(&plist);
92. SLTPopFront(&plist);
93. SLTPopFront(&plist);
94. SLTPopFront(&plist);
95. SLTPopFront(&plist);
96. SLTPopFront(&plist);
97. SLTPopFront(&plist);
98. SLTprintf(plist);
99.     ret=Totalsize(&plist);
100. printf("total is :%d\n",ret);
101. }
102. void test6(void)
103. {
104.     SLT* plist=NULL;
105. //   SLTPushFront(&plist, 1);
106. //    SLTPushFront(&plist, 2);
107. //    SLTPushFront(&plist, 3);
108. //    SLTPushFront(&plist, 4);
109. //    SLTPushBack(&plist, 4);
110. //    SLTPushBack(&plist, 3);
111. //    SLTPushBack(&plist, 2);
112. //    SLTPushBack(&plist, 1);
113. SLTprintf(plist);
114. SLTInsertAfter(&plist, 1, 100);
115. SLTprintf(plist);
116. }
117. void test7(void)
118. {
119.     SLT* plist=NULL;
120. SLTPushFront(&plist, 1);
121. //    SLTPushFront(&plist, 2);
122. //    SLTPushFront(&plist, 3);
123. //    SLTPushFront(&plist, 4);
124. //    SLTPushBack(&plist, 4);
125. //    SLTPushBack(&plist, 3);
126. //    SLTPushBack(&plist, 2);
127. //    SLTPushBack(&plist, 1);
128. SLTprintf(plist);
129. SLTEraseAfter(&plist, 1);
130. SLTprintf(plist);
131. }
132. void test8(void)
133. {
134.     SLT* plist=NULL;
135. SLTPushFront(&plist, 1);
136. SLTPushFront(&plist, 2);
137. SLTPushFront(&plist, 3);
138. SLTPushFront(&plist, 4);
139. SLTPushBack(&plist, 4);
140. SLTPushBack(&plist, 3);
141. SLTPushBack(&plist, 2);
142. SLTPushBack(&plist, 1);
143. SLTprintf(plist);
144. SLTDestroy(&plist);
145. SLTprintf(plist);
146. }
147. int main()
148. {
149. //test1();//完成头插尾插
150. //test2();//完成尾删
151. //test3();//查找
152. //test4();//改动
153. //test5();//判断链表有多少个元素
154. // test6();//任意插入元素
155. //test7();//任意删除元素
156. test8();//销毁链表
157. }

🌸头文件test.h

1. #ifndef test_h
2. #define test_h
3. #include <stdio.h>
4. #endif /* test_h */
5. #include<stdlib.h>
6. #include<assert.h>
7. 
8. typedef int SLTDataType;
9. typedef struct SListNode
10. {
11.     SLTDataType data;
12. struct SListNode* next;//next存放的下一个节点的地址
13. }SLT;
14. 
15. //单链表的打印
16. void SLTprintf(SLT* phead);
17. //单链表的头插
18. void SLTPushFront(SLT** pphead,SLTDataType x);
19. //单链表的尾插
20. void SLTPushBack(SLT** pphead,SLTDataType x);
21. //单链表的尾删
22. void SLTPopBack(SLT** pphead);
23. //单链表的头删
24. void SLTPopFront(SLT** pphead);
25. //单链表的查找(找到了,就返回所在的位置,没找到返回-1)
26. int SLTFind(SLT** pphead,SLTDataType x);
27. //单链表的改动(改变给出位置的值)
28. void SLTChange(SLT** pphead,int pos,SLTDataType x);
29. //单链表的元素个数
30. int Totalsize(SLT** pphead);
31. //单链表的任意位置插入元素
32. void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x);
33. //单链表的任意位置删除元素
34. void SLTEraseAfter(SLT** pphead,int pos);
35. //单链表的销毁
36. void SLTDestroy(SLT** pphead);

🌸test.c文件

1. #include "test.h"
2. 
3. void SLTprintf(SLT* phead)
4. {
5.     SLT* cur=phead;
6. while(cur!=NULL)
7.     {
8. printf("%d ",cur->data);
9.         cur=cur->next;
10.     }
11. printf("\n");
12. }
13. SLT* Buylistnode(int x)
14. {
15.     SLT* newnode=(SLT*)malloc(sizeof(SLT));
16. if(newnode==NULL)
17.     {
18. perror("malloc fail");
19. return 0;
20.     }
21.     newnode->data=x;
22.     newnode->next=NULL;
23. return newnode;
24. }
25. void SLTPushFront(SLT** pphead,SLTDataType x)
26. {
27.     SLT* newnode= Buylistnode(x);
28.     newnode->next=*pphead;
29.     *pphead=newnode;
30. }
31. void SLTPushBack(SLT** pphead,SLTDataType x)
32. {
33.     SLT* newnode=Buylistnode(x);
34. if(*pphead==NULL)
35.     {
36.         *pphead=newnode;
37.     }
38. else
39.     {
40.         SLT* tail=*pphead;
41. while(tail->next)
42.         {
43.             tail=tail->next;
44.         }
45.         tail->next=newnode;
46.     }
47. }
48. //这两种方法的本质都是找到倒数第二个节点
49. //第一种尾删的方法
50. void SLTPopBack(SLT** pphead)
51. {
52. assert(*pphead);
53.     SLT* prev=NULL;
54.     SLT* tail=*pphead;
55. if(tail->next==NULL)
56.     {
57. free(tail);
58.         *pphead=NULL;
59.     }
60. else
61.     {
62. while(tail->next)
63.         {
64.             prev=tail;
65.             tail=tail->next;
66.         }
67. free(tail);
68.         prev->next=NULL;
69.     }
70. }
71. //第二种尾删的方法
72. //void SLTPopBack(SLT** pphead)
73. //{
74. //    assert(*pphead);
75. //    SLT* tail=*pphead;
76. //    if(tail->next==NULL)//只有一个节点
77. //    {
78. //        free(tail);
79. //        *pphead=NULL;
80. //    }
81. //    else//有多个节点
82. //    {
83. //        while(tail->next->next)//这也是找到倒数第二个节点
84. //        {
85. //            tail=tail->next;
86. //        }
87. //        free(tail->next);
88. //        tail->next=NULL;
89. //    }
90. //}
91. 
92. 
93. 
94. void SLTPopFront(SLT** pphead)
95. {
96. assert(*pphead);
97.     SLT* tail=*pphead;
98. if(tail->next==NULL)//一个节点
99.     {
100. free(tail);
101.         *pphead=NULL;
102.     }
103. else//多个节点
104.     {
105.         tail=tail->next;
106. free(*pphead);
107.         *pphead=tail;
108.     }
109. }
110. 
111. int SLTFind(SLT** pphead,SLTDataType x)
112. {
113. assert(*pphead);
114.     SLT* try_b=*pphead;
115. int Count=1;
116. while(try_b->next)
117.     {
118. if(try_b->data==x)
119.         {
120. return Count;
121.         }
122.         Count++;
123.         try_b=try_b->next;
124.     }
125. return  -1;
126. }
127. int Totalsize(SLT** pphead)
128. {
129.     SLT* tail=*pphead;
130. int Count=0;
131. while(tail)
132.     {
133.         tail=tail->next;
134.         Count++;
135.     }
136. return Count;
137. }
138. void SLTChange(SLT** pphead,int pos,SLTDataType x)
139. {
140. assert(*pphead);
141. int Count=Totalsize(pphead);
142. assert(pos<=Count);
143.     SLT* tail=*pphead;
144. while(pos--)
145.     {
146.         tail=tail->next;
147.     }
148.     tail->data=x;
149. }
150. 
151. void SLTInsertAfter(SLT** pphead,int pos, SLTDataType x)
152. {
153. if((*pphead)==NULL)
154.     {
155. SLTPushFront(pphead, x);
156.     }
157. else
158.     {
159.         SLT* prev=NULL;
160.         SLT* tail=*pphead;
161. while(pos--)
162.         {
163.             prev=tail;
164.             tail=tail->next;
165.         }
166.         SLT* newnode=Buylistnode(x);
167.         prev->next=newnode;
168.         newnode->next=tail;
169.     }
170. }
171. 
172. void SLTEraseAfter(SLT** pphead,int pos)
173. {
174. assert(*pphead);
175. if((*pphead)->next==NULL)
176.    {
177. SLTPopFront(pphead);
178.    }
179. else
180.     {
181.         SLT* prev=NULL;
182.         SLT* taillater=NULL;
183.         SLT* tail=*pphead;
184. while(pos--)
185.         {
186.             prev=tail;
187.             tail=tail->next;
188.         }
189.         taillater=tail->next;
190. free(tail);
191.         tail=NULL;
192.         prev->next=taillater;
193.     }
194. }
195. 
196. void SLTDestroy(SLT** pphead)
197. {
198. free(*pphead);
199.     *pphead=NULL;
200. }

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸



相关文章
|
23天前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
34 1
|
1月前
|
存储 算法 搜索推荐
【趣学C语言和数据结构100例】91-95
本文涵盖多个经典算法问题的C语言实现,包括堆排序、归并排序、从长整型变量中提取偶数位数、工人信息排序及无向图是否为树的判断。通过这些问题,读者可以深入了解排序算法、数据处理方法和图论基础知识,提升编程能力和算法理解。
45 4
|
1月前
|
存储 机器学习/深度学习 搜索推荐
【趣学C语言和数据结构100例】86-90
本文介绍并用C语言实现了五种经典排序算法:直接插入排序、折半插入排序、冒泡排序、快速排序和简单选择排序。每种算法都有其特点和适用场景,如直接插入排序适合小规模或基本有序的数据,快速排序则适用于大规模数据集,具有较高的效率。通过学习这些算法,读者可以加深对数据结构和算法设计的理解,提升解决实际问题的能力。
43 4
|
1月前
|
存储 算法 数据处理
【趣学C语言和数据结构100例】81-85
本文介绍了五个经典算法问题及其C语言实现,涵盖图论与树结构的基础知识。包括使用BFS求解单源最短路径、统计有向图中入度或出度为0的点数、统计无向无权图各顶点的度、折半查找及二叉排序树的查找。这些算法不仅理论意义重大,且在实际应用中极为广泛,有助于提升编程能力和数据结构理解。
39 4
|
1月前
|
算法 数据可视化 数据建模
【趣学C语言和数据结构100例】76-80
本文介绍了五种图论算法的C语言实现,涵盖二叉树的层次遍历及广度优先搜索(BFS)和深度优先搜索(DFS)的邻接表与邻接矩阵实现。层次遍历使用队列按层访问二叉树节点;BFS利用队列从源节点逐层遍历图节点,适用于最短路径等问题;DFS通过递归或栈深入图的分支,适合拓扑排序等场景。这些算法是数据结构和算法学习的基础,对提升编程能力和解决实际问题至关重要。
49 4
|
1月前
|
存储 算法 vr&ar
【趣学C语言和数据结构100例】71-75
本文介绍了五个C语言数据结构问题及其实现,涵盖链表与二叉树操作,包括按奇偶分解链表、交换二叉树左右子树、查找节点的双亲节点、计算二叉树深度及求最大关键值。通过递归和遍历等方法,解决了理论与实际应用中的常见问题,有助于提升编程能力和数据结构理解。
37 4
|
1月前
|
存储 算法 C语言
【趣学C语言和数据结构100例】66-70
本书《趣学C语言和数据结构100例》精选了5个典型的数据结构问题及C语言实现,涵盖链表与数组操作,如有序集合的集合运算、有序序列表的合并、数组中两顺序表位置互换、三递增序列公共元素查找及奇偶数重排。通过详细解析与代码示例,帮助读者深入理解数据结构与算法设计的核心思想,提升编程技能。
34 4
|
24天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
45 5
|
23天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
54 1
|
1月前
|
存储 机器学习/深度学习 算法
【趣学C语言和数据结构100例】61-65
本文介绍了五个关于C语言和数据结构的经典问题及其实现方法,涵盖查找链表共同后缀、删除重复节点、重新排列链表元素、合并有序链表以及特定条件下的链表排序。每个问题通过具体的算法设计,不仅展示了链表操作的灵活性,还强调了效率优化的重要性。通过这些问题的探讨,读者可以深入理解链表的基本操作和高级应用,提升解决实际问题的能力。
46 4