//VS2022 x86编译器下已测试通过
//C语言 链表的基本使用 -- 13个函数,初始化(头插、尾插)、遍历打印、获取元素总个数、插入(按值前插/后插、按位置)、删除(按值、按位置)、逆置、清空、销毁
//如果在CLion中使用,请将这三个文件放在CMakeLists.txt的同级目录下,在CMakeLists.txt中添加如下内容,生成程序后,在终端切换到对应的exe所在文件夹,之后输入程序名称(.\Demo.exe) 即可开始运行。或者Run程序,之后在Run的窗口中,修改如下:Edit Run Configuration -- 勾选Run in external console,之后Rerun,也可以运行。测试代码输入1,2,3,4,5,-1,即可得到Demo.c文件中那些被注释的链表结果。
include_directories(.) add_executable(Demo Demo.c linklist.c)
示例代码:三个文件,linklist.h、linklist.c 和Demo.c
linklist.h代码:
1 #pragma once
2
3 #define _CRT_SECURE_NO_WARNINGS
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 //定义结点
9 struct LinkNode
10 {
11 int num;
12 struct LinkNode* next;
13 };
14
15 //01.初始化链表:尾插法:可以使遍历链表得出的数据和输入的数据顺序相同
16 struct LinkNode* initLinkListTail();
17
18 //02.初始化链表:头插法:可以使遍历链表得出的数据和输入的数据顺序相反
19 struct LinkNode* initLinkListHead();
20
21 //03.遍历链表,并打印输出
22 void foreach_LinkList(struct LinkNode* pHeader);
23
24 //04.获取链表长度,获取链表中元素个数
25 int getElementNums(struct LinkNode* pHeader);
26
27 //05.获取链表中某位置对应的结点的值,假设头结点为第0个结点,pos为链表中第pos个结点
28 int getValueByPos(struct LinkNode* pHeader, int pos);
29
30 //06.向链表插入新结点(根据结点值):到现存结点前面或末尾
31 void insert_LinkListByValueBefore(struct LinkNode* pHeader, int oldVal, int newVal);
32
33 //07.向链表插入新结点(根据结点值):到现存结点后面或末尾,尾插法
34 void insert_LinkListByValueAfter(struct LinkNode* pHeader, int oldVal, int newVal);
35
36 //08.向链表插入新节点(根据给定位置):位置需要为大于0的数
37 void insert_LinkListByPos(struct LinkNode* pHeader, int pos, int newVal);
38
39 //09.删除链表(根据给定结点值):删除链表中某个结点
40 void delete_LinkListByValue(struct LinkNode* pHeader, int delVal);
41
42 //10.删除链表(根据给定位置):删除链表中某个结点
43 void delete_LinkListByPos(struct LinkNode* pHeader, int pos);
44
45 //11.反转链表:逆置
46 void reverse_LinkList(struct LinkNode* pHeader);
47
48 //12.清空链表(可以复用):清空各结点数据域,保留指针域,保留头结点
49 void clear_LinkList(struct LinkNode* pHeader);
50
51 //13.销毁链表:头结点和之后所有结点全部删除,一个不留
52 void destroy_LinkList(struct LinkNode* pHeader);
View Code
linklist.c代码
1 #include "linklist.h"
2
3
4
5 //01.尾插法:初始化链表,函数返回值是创建好的链表的头结点
6 struct LinkNode* initLinkListTail()
7 {
8 struct LinkNode* pHeader = (struct LinkNode*)malloc(sizeof(struct LinkNode));
9 if (pHeader == NULL)
10 {
11 return NULL;
12 }
13
14 pHeader->next = NULL;
15 struct LinkNode* pTail = pHeader;
16 int val = -1;
17 while (1)
18 {
19 printf("请初始化链表,输入一个数字,并按Enter键,如果输入-1则代表结束\n");
20 scanf("%d", &val);
21 if (val == -1)
22 {
23 break;
24 }
25 struct LinkNode* newNode = (struct LinkNode*)malloc(sizeof(struct LinkNode));
26 newNode->num = val;
27 newNode->next = NULL;
28
29 pTail->next = newNode;
30 pTail = newNode;
31 }
32
33 return pHeader;
34 }
35
36
37 //02.头插法:初始化链表,函数返回值是创建好的链表的头结点
38 struct LinkNode* initLinkListHead()
39 {
40 struct LinkNode* pHeader = (struct LinkNode*)malloc(sizeof(struct LinkNode));
41 if (pHeader == NULL)
42 {
43 return NULL;
44 }
45
46 pHeader->next = NULL;
47 //struct LinkNode* pTail = pHeader;
48 int val = -1;
49 while (1)
50 {
51 printf("请初始化链表,如果输入-1代表结束\n");
52 scanf("%d", &val);
53 if (val == -1)
54 {
55 break;
56 }
57 struct LinkNode* newNode = (struct LinkNode*)malloc(sizeof(struct LinkNode));
58 newNode->num = val;
59 newNode->next = pHeader->next;
60
61 pHeader->next = newNode;
62 //pTail = newNode;
63 }
64
65 return pHeader;
66 }
67
68
69 //03.遍历链表,并打印输出
70 void foreach_LinkList(struct LinkNode* pHeader)
71 {
72 if (pHeader == NULL)
73 {
74 return;
75 }
76 struct LinkNode* pCurrent = pHeader->next;
77 int i = 0;
78 while (pCurrent != NULL)
79 {
80 printf("链表中第%d个结点的数据域的值为: %d\n", i + 1, pCurrent->num);
81 i++;
82 pCurrent = pCurrent->next;
83 }
84 }
85
86
87 //04.获取链表长度,获取链表中元素个数
88 int getElementNums(struct LinkNode* pHeader)
89 {
90 int nums = 0;
91 if (pHeader == NULL)
92 {
93 return 0;
94 }
95 struct LinkNode* pCurrent = pHeader->next;
96
97 while (pCurrent != NULL)
98 {
99 nums++;
100 pCurrent = pCurrent->next;
101 }
102 return nums;
103 }
104
105
106 //05.获取链表中某位置对应的结点的值,假设头结点为第0个结点,pos为链表中第pos个结点
107 int getValueByPos(struct LinkNode* pHeader, int pos)
108 {
109 struct LinkNode* tmpHeader = pHeader;
110 if (pHeader == NULL)
111 {
112 return -1;
113 }
114
115 int lens = getElementNums(pHeader);
116 if (pos <= 0)
117 {
118 printf("位置值不得为负数或0。请输入正确的位置\n");
119 return -1;
120 }
121 if (pos > lens)
122 {
123 printf("位置值不得大于元素中的个数值,现在链表中已有%d个元素。请输入正确的位置\n", lens);
124 return -1;
125 }
126
127 int i = 0;
128 while (i < pos)
129 {
130 tmpHeader = tmpHeader->next;
131 i++;
132 }
133 int value = tmpHeader->num;
134
135 return value;
136 }
137
138
139 //06.向链表插入新结点(根据结点值):到现存结点前面或末尾,如果存在该0ldVal值,就创建新节点,赋值为newVal,并插入到oldVal结点前面,如果不存在,则创建一个新结点,并插入到现有链表的尾部,新节点成为链表中最后一个结点。
140 void insert_LinkListByValueBefore(struct LinkNode* pHeader, int oldVal, int newVal)
141 {
142 if (pHeader == NULL)
143 {
144 return;
145 }
146
147 //创建两个临时的节点
148 struct LinkNode* pPrve = pHeader;
149 struct LinkNode* pCurrent = pHeader->next;
150
151 while (pCurrent != NULL)
152 {
153 if (pCurrent->num == oldVal)
154 {
155 break;
156 }
157 //如果没找到对应的位置,辅助指针向后移动
158 pPrve = pCurrent;
159 pCurrent = pCurrent->next; //如果没找到oldVal,则pCurrent = pCurrent->next = NULL;
160 }
161
162 //创建新节点
163 struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
164 newNode->num = newVal;
165 newNode->next = NULL;
166
167
168 //建立关系
169 newNode->next = pCurrent; //如果没找到,则pCurrent=NULL
170 pPrve->next = newNode; //将新节点挂在pPrve的后面,即如果找到就是oldVal前面的一个结点,如果没找到就是链表最后一个结点。
171
172 }
173
174
175 //07.向链表插入新结点(根据结点值):到现存结点后面或末尾,如果存在该0ldVal值,就创建新节点,赋值为newVal,并插入到oldVal结点前面,如果不存在,则创建一个新结点,并插入到现有链表的尾部,新节点成为链表中最后一个结点。
176 void insert_LinkListByValueAfter(struct LinkNode* pHeader, int oldVal, int newVal)
177 {
178 if (pHeader == NULL)
179 {
180 return;
181 }
182
183 //创建两个临时的节点
184 struct LinkNode * pTail = pHeader;
185 struct LinkNode* pCurrent = pHeader->next;
186 int flag = 0;
187
188 while (pCurrent != NULL)
189 {
190 if (pCurrent->num == oldVal)
191 {
192 flag = 1;
193 break;
194 }
195 //如果没找到对应的位置,辅助指针向后移动
196 pTail = pCurrent;
197 pCurrent = pCurrent->next; //如果没找到oldVal,则pCurrent = pCurrent->next = NULL;
198 }
199 if (flag == 1)
200 {
201 struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
202 newNode->num = newVal;
203 newNode->next = pCurrent->next;
204 pCurrent->next = newNode;
205 }
206 else {
207 //printf("未找到,失败\n");
208 struct LinkNode* newNode = malloc(sizeof(struct LinkNode));
209 newNode->num = newVal;
210 newNode->next = NULL;
211
212 //更改指针的指向
213 pTail->next = newNode;
214 //更新新的尾节点的指向
215 pTail = newNode;
216 }
217 }
218
219
220 //08.向链表插入新节点(根据给定位置):位置需要为大于0的数
221 void insert_LinkListByPos(struct LinkNode* pHeader, int pos, int newVal)
222 {
223 int num = getValueByPos(pHeader, pos);
224
225 //printf("此时:pos= %d, num = %d\n", pos, num); //此时pos等于i
226 if (num == -1)
227 {
228 printf("当前pos参数输入错误,本次插入失败\n");
229 }
230 else {
231 insert_LinkListByValueBefore(pHeader, num, newVal);
232 }
233 }
234
235
236 //09.删除链表(根据给定结点值):删除链表中某个结点
237 void delete_LinkListByValue(struct LinkNode* pHeader, int delVal)
238 {
239 if (pHeader == NULL)
240 {
241 return;
242 }
243
244 //创建两个辅助指针变量
245 struct LinkNode* pPrev = pHeader;
246 struct LinkNode* pCurrent = pHeader->next;
247
248 while (pCurrent != NULL)
249 {
250 if (pCurrent->num == delVal)
251 {
252 break;
253 }
254 //没有找到数据,辅助指针向后移动
255 pPrev = pCurrent;
256 pCurrent = pCurrent->next;
257 }
258
259 if (pCurrent == NULL) //没有找到用户要删除的数据
260 {
261 return;
262 }
263
264 //更改指针的指向进行删除
265 pPrev->next = pCurrent->next;
266
267 //删除掉待删除的节点
268 free(pCurrent);
269 pCurrent = NULL;
270 }
271
272
273 //10.删除链表(根据给定位置):删除链表中某个结点
274 void delete_LinkListByPos(struct LinkNode* pHeader, int pos)
275 {
276 int num = getValueByPos(pHeader, pos);
277 if (num == -1)
278 {
279 printf("当前pos参数输入错误,本次删除失败\n");
280 }
281 else {
282 delete_LinkListByValue(pHeader, num);
283 }
284 }
285
286
287 //11.反转链表:逆置 -- 我写的
288 void reverse_LinkList1(struct LinkNode* pHeader)
289 {
290 if (pHeader == NULL)
291 {
292 return;
293 }
294
295 struct LinkNode* pCurrent = pHeader->next;
296
297 if (pCurrent == NULL)
298 {
299 printf("空链表,逆置失败。\n");
300 return;
301 }
302
303 pHeader->next = NULL;
304
305 int tmpValue = pCurrent->next;
306 while (pCurrent != NULL)
307 {
308 insert_LinkListByValueBefore(pHeader, tmpValue, pCurrent->num);
309 tmpValue = pCurrent->num;
310 pCurrent = pCurrent->next;
311 }
312 //删除掉待删除的节点
313 free(pCurrent);
314 pCurrent = NULL;
315 }
316
317 //11-1.反转链表:逆置 -- 课程老师给定
318 void reverse_LinkList(struct LinkNode* pHeader)
319 {
320 if (pHeader == NULL)
321 {
322 return;
323 }
324
325 struct LinkNode* pCurrent = pHeader->next;
326 struct LinkNode* pPrev = NULL;
327 struct LinkNode* pNext = NULL;
328
329 while (pCurrent != NULL)
330 {
331 pNext = pCurrent->next;
332 //更改指针指向
333 pCurrent->next = pPrev;
334
335 //移动辅助指针
336 pPrev = pCurrent;
337 pCurrent = pNext;
338 }
339
340 //更新头结点
341 pHeader->next = pPrev;
342
343 }
344
345 //12.清空链表(可以复用):清空各结点数据域,保留指针域,保留头结点
346 void clear_LinkList(struct LinkNode* pHeader)
347 {
348 if (pHeader == NULL)
349 {
350 return;
351 }
352
353 struct LinkNode* pCurrent = pHeader->next;
354
355 while (pCurrent != NULL)
356 {
357 //先保存住下一个节点的位置
358 struct LinkNode* nextNode = pCurrent->next;
359
360 free(pCurrent);
361
362 pCurrent = nextNode;
363 }
364
365 pHeader->next = NULL;
366 }
367
368
369 //13.销毁链表:头结点和之后所有结点全部删除,一个不留
370 void destroy_LinkList(struct LinkNode* pHeader)
371 {
372 if (pHeader == NULL)
373 {
374 return;
375 }
376
377 //先清空链表
378 clear_LinkList(pHeader);
379
380 //再释放头节点
381
382 free(pHeader);
383 pHeader = NULL;
384 }
View Code
Demo.c代码
1 #define _CRT_SECURE_NO_WARNINGS
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "linklist.h"
6
7 //如果是学习之用,可以将注释分布取消,以观察输出的结果,如果是用例的调用需要,可以直接将注释全部删除
8 void test01()
9 {
10 //初始化
11 struct LinkNode* pHeader = initLinkListTail(); //假设输入1,2,3,4,5,-1 ,尾插法
12 //struct LinkNode* pHeader = initLinkListHead();
13
14 //遍历
15 foreach_LinkList(pHeader); //尾插法:1,2,3,4,5 ;头插法:5,4,3,2,1
16
17 //获取元素个数
18 int lens = getElementNums(pHeader);
19 printf("lens = %d\n", lens); //lens = 5
20 printf("间隔行:1*********************************************\n\n");
21
22 //向链表插入新结点(根据结点值):到现存结点前面或末尾
23 //insert_LinkListByValueBefore(pHeader,3, 8); //在链表中如果找到对应给定值的结点,就在该节点的前面插入
24 //foreach_LinkList(pHeader);//1,2,8,3,4,5
25 //printf("间隔行:2*********************************************\n\n");
26 //insert_LinkListByValueBefore(pHeader, 6, 9); //在链表中如果没有找到给定值的结点,就在最后插入
27 //foreach_LinkList(pHeader);//1,2,8,3,4,5,9
28 //printf("间隔行:3*********************************************\n\n");
29
30 //向链表插入新结点(根据结点值):到现存结点后面或末尾,尾插法
31 //insert_LinkListByValueAfter(pHeader, 3, 10);//在链表中如果找到给定值的结点,就在该结点的后面插入
32 //foreach_LinkList(pHeader);//1,2,8,3,10,4,5,9
33 //printf("间隔行:4*********************************************\n\n");
34 //insert_LinkListByValueAfter(pHeader, 6, 11);//在链表中如果没有找到给定值的结点,就在最后插入
35 //foreach_LinkList(pHeader);//1,2,8,3,10,4,5,9,11
36 //printf("间隔行:5*********************************************\n\n");
37
38 //向链表插入新节点(根据给定位置):位置需要为大于0的数
39 //insert_LinkListByPos(pHeader, 0,12);
40 insert_LinkListByPos(pHeader, 3, 12);
41 //insert_LinkListByPos(pHeader, 5, 12);
42 //insert_LinkListByPos(pHeader, 6, 12);
43 foreach_LinkList(pHeader); //1,2,12,3,4,5
44 printf("间隔行:6*********************************************\n\n");
45
46 //删除链表(根据给定结点值):删除链表中某个结点
47 delete_LinkListByValue(pHeader, 12);
48 foreach_LinkList(pHeader); //1,2,3,4,5
49 printf("间隔行:7*********************************************\n\n");
50 //delete_LinkListByValue(pHeader, 4);
51 //foreach_LinkList(pHeader); //1,2,12,3,4,5
52 //printf("间隔行:8*********************************************\n\n");
53 //delete_LinkListByValue(pHeader, 8); //链表中并没有8,不做删除
54 //foreach_LinkList(pHeader); //1,2,12,3,4,5
55 //printf("间隔行:9********************************************\n\n");
56
57 //删除链表(根据给定位置):删除链表中某个结点
58 delete_LinkListByPos(pHeader, 3);
59 foreach_LinkList(pHeader); //1,2,4,5
60 lens = getElementNums(pHeader);
61 printf("lens = %d\n", lens); //lens = 4
62 delete_LinkListByPos(pHeader, lens);
63 foreach_LinkList(pHeader); //1,2,4
64 lens = getElementNums(pHeader);
65 printf("lens = %d\n", lens); //lens = 3
66 printf("间隔行:10*********************************************\n\n");
67
68
69 //反转链表:逆置
70 reverse_LinkList(pHeader);
71 foreach_LinkList(pHeader); //4,2,1
72 lens = getElementNums(pHeader);
73 printf("lens = %d\n", lens); //lens = 3
74 printf("间隔行:11*********************************************\n\n");
75
76 //清空链表(可以复用):清空各结点数据域,保留指针域,保留头结点
77 clear_LinkList(pHeader);
78 foreach_LinkList(pHeader); //不打印
79 lens = getElementNums(pHeader);
80 printf("lens = %d\n", lens); //lens = 0
81 printf("间隔行:12*********************************************\n\n");
82
83 //销毁链表:头结点和之后所有结点全部删除,一个不留
84 destroy_LinkList(pHeader);
85 pHeader = NULL;
86 printf("间隔行:13*********************************************\n\n");
87
88
89 }
90
91 int main()
92 {
93 test01();
94
95 printf("\n");
96 system("pause");
97 return 0;
98 }
View Code
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我有这样的哈希trial_hash={"key1"=>1000,"key2"=>34,"key3"=>500,"key4"=>500,"key5"=>500,"key6"=>500}我按值降序排列:my_hash=trial_hash.sort_by{|k,v|v}.reverse我现在是这样理解的:[["key1",1000],["key4",500],["key5",500],["key6",500],["key3",500],["key2",34]]但我希望当值相同时按键的升序排序。我该怎么做?例如:上面的散列将以这种方式排序:[["key1",1000],["key3",500
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc
我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit