带头节点的线性链表类型[原创]
1/*========带头节点的线性链表类型=========*/
2/*=======================================*/
3
4
5/*===============包含头文件以及类型定义==============*/
6#include <stdio.h>
7#include <malloc.h>
8#define NULL 0
9#define NODE_NUM 10
10
11
12typedef struct lnode{
13 char data;
14 struct lnode *next;
15}*link,*position;
16
17
18typedef struct{
19 link head,tail;
20 int len;
21}linklist;
22
23
24/*======================================================*/
25/*=======一些在其他函数定义中会调用的函数===============*/
26/*======================================================*/
27
28int compare(char a,char b){ /*---compare---比较两个元素的大小关系*/
29 return a-b;
30}
31
32
33int visit(link p){
34 if(p->data>=65&&p->data<=97)/*---visit---判断结点的元素是否为大写元素*/
35 return 1;
36 else
37 return 0;
38
39}
40
41
42int length(link s){ /*---length---求链的长度*/
43 int i=0;/*i不赋初值,编译错误“可能在i定义以前使用了它在length函数中”*/
44 link p=NULL;
45 p=s;
46 while(p->next!=NULL){
47 p=p->next;
48 i++;
49 }
50 return i;
51}
52
53
54void print(linklist l){ /*---print---在屏幕上输出链表的所有元素*/
55 link p=NULL;
56 p=l.head;
57 if(!p->next){
58 printf("\nThe linklist is empty.\n\n");
59 return ;
60 }
61 printf("The list:");
62 while(p){
63 printf("%c-",p->data);
64 p=p->next;
65 }
66}
67
68
69
70/*======================================================*/
71/*==========对带头结点的单链线性表进行操作的函数的定义==================*/
72/*======================================================*/
73
74position makenode(char e){ /*---分配由p指向的结点并赋值为e---*/
75 link p=NULL;
76 p=(link)malloc(sizeof(struct lnode));
77 /*---struct lnode 才能表示一个结构体类型并可用于分配空间的元素类型定义-*/
78 if(p){
79 p->data=e;
80 p->next=NULL;
81 }
82 else return;
83 return p;
84}
85
86
87void freenode(link p){ /*---释放p所指向的结点-*/
88 free(p);
89}
90
91
92
93int initlist(linklist *l){ /*---构造一个由l指向的空的线性表-*/
94 l->head=makenode('L');
95 l->head->next=NULL;/*不是l->head=NULL*/
96 l->tail=l->head;
97 l->len=0;
98 return 1;
99}
100
101
102position priorpos(linklist l,link p){ /*---返回p所指结点的直接前驱的位置-*/
103 link q;
104 q=l.head;
105 if(q->next==p) return 0;
106 while(q->next!=p) q=q->next;
107 return q;
108}
109
110
111int insfirst(linklist *l,link s){ /*---将s指向的结点插入线性链表的第一个结点之前-*/
112 s->next=l->head->next;
113 if(!l->head->next) l->tail=s;/*当向一个空的线性表执行该操作时*/
114 l->head->next=s;
115 l->len++;
116
117}
118
119
120int append(linklist *l,link s){ /*---将指针s所的一串结点链接在线性表L的最后一个结点-*/
121 link q;
122 q=l->head;
123 if(!l->tail){/*考虑到链表为空的情况*/
124 l->head->next=s;
125 while(q->next) q=q->next;/*尾结点的处理*/
126 l->tail=q;
127 }
128 l->tail->next=q=s;
129 while(q->next) q=q->next;/*不能忘了对尾结点的处理*/
130 l->tail=q;
131 l->len+=length(s);
132
133}
134
135position delfirst(linklist *l,link q){ /*---删除表中第一个结点并以q返回-*/
136 if(!l->head->next){
137 printf("\nThe linklist is empty,can not delete..\n");
138 return 0;
139 }
140 q=l->head->next;
141 l->head->next=l->head->next->next;
142 return q;
143}
144
145
146position remonode(linklist *l,link q){ /*---删除线性表l中的尾结点-*/
147 if(!l->tail){
148 printf("\nthe linklist is empty,can not remonde..\n");
149 return 0;
150 }
151 q=l->tail; /*用书上函数名remove时,编译错误“调用参数个数出错”*/
152 l->tail=priorpos(*l,q);
153 l->tail->next=NULL;
154 return q;
155}
156
157
158int insbefore(linklist *l,link p,link s){ /*---将s所指向结点插入在p所指结点之前-*/
159 link q;
160 q=priorpos(*l,p);
161 s->next=p;
162 q->next=s;
163}
164
165
166int insafter(link p,link s){ /*---将s所指向结点插入在p所指结点之后-*/
167 s->next=p->next;
168 p->next=s;
169}
170
171
172int setcurelem(link p,char e){ /*---用e更新p所指向的当前结点-*/
173 p->data=e;
174}
175
176
177char getcurelem(link p){ /*---返回p所指结点中元素的值-*/
178 return p->data;
179}
180
181
182int listempty(linklist l){ /*---若线性表为空表则返回1,否则返回0-*/
183 if(l.head==l.tail) return 1;
184 return 0;
185}
186
187
188int listlength(linklist l){ /*---返回线性表中元素个数-*/
189 return l.len;
190}
191
192
193position gethead(linklist l){ /*---返回线性表l中头结点的位置-*/
194 return l.head;
195}
196
197
198position getlast(linklist l){ /*-----返回线性表l中最后一个结点的位置-------*/
199 return l.tail;
200}
201
202
203position nextpos(link p){ /*-----返回p所指结点的直接后继的位置-------*/
204 link q;
205 q=p->next;
206 return q;
207}
208
209
210position locatepos(linklist l,int i,link p){ /*-----用p返回线性表l中第i个结点的位置,并返回ok-------*/
211 p=l.head;
212 if(i<=0||i>listlength(l)) return 0;
213 while(i){
214 p=p->next;
215 i--;
216 }
217 return p;
218}
219
220
221int locatelem(linklist l,char e){ /*----返回表中第一个与e满足一定函数关系的结点次序位置--------*/
222 int i=0;
223 link p;
224 p=l.head->next;
225 while(compare(p->data,e)&&p){
226 p=p->next;
227 ++i;
228 }
229 if(!p){/*考虑到查找不到指定元素的情况*/
230 printf("\nthere's no '%c' in this linklist.",e);
231 return 0;
232 }
233 return i;
234}
235
236
237int listraverse(linklist l){ /*----用一个函数遍历表中所有结点-------*/
238 link p;
239 p=l.head;
240 while(!visit(p)) p=p->next;
241 if(p!=l.tail) return 0;
242
243}
244
245
246
247
248
249int clearlist(linklist*l){ /*----?------将线性表l置为空表,并释放原链表的结点?*/
250 link p;
251 p=(*l).tail;
252 while(p!=(*l).head){
253 p=priorpos(*l,p);
254 freenode(p->next);
255 }
256 freenode((*l).head);
257
258}
259
260int destroylist(linklist *l){ /*----------销毁由l指向的线性表---------*/
261 link p;
262 p=(*l).tail;
263 while(p!=(*l).head){
264 p=priorpos(*l,p);
265 freenode(p->next);
266 }
267 freenode((*l).head);
268}
269
270
271
272
273
274/*=======================================================*/
275/*==================主函数部分===================*/
276/*=======================================================*/
277main(){
278 int i;
279 char temp='a';
280 linklist *l,*la=NULL,*lb,*lc=NULL;
281 link s,s_nodes,q,p,n;
282
283
284 initlist(l);
285 /*调用初始化函数,构造一个由l指向的线性链表*/
286 printf("l->head->data:%c ",l->head->data);
287 print(*l);
288
289 for(i=1;i<=5;i++){
290 s=makenode(temp++);/*每次插入结点都要重新分配空间,否则无限循环*/
291 insfirst(l,s);
292 /*将s指向的结点插入在以(*l).head为头结点的链表的第一个元素之前*/
293 }
294 printf("insfirst(l,s)*5, ");
295 print(*l);
296
297 s_nodes=s=makenode(temp++);/*_1_*/
298 printf("\ns_nodes:");
299 for(i=1;i<=NODE_NUM;i++){
300 s->next=makenode(temp++);/*_2_*/
301 printf("%c ",s->data);
302 s=s->next;
303 }/*构造了一串由s_nodes指向的链,并为其中的数据项赋值*/
304
305 append(l,s_nodes);
306 /*将由s_nodes指向的一串结点附加到l指向的链表的后面*/
307 printf("\nappend(l,s_nodes), ");
308 print(*l);
309
310 q=delfirst(l,q);/*---*/
311 /*删除以(*l).head为头结点的链表中的第一个结点并以q返回*/
312 printf("\ndelfirst(l,q), ");
313 print(*l);
314 printf("\nthe deleted element:%c",q->data);
315
316 q=remonode(l,q);
317 /*删除l指向的线性表的尾结点并以q返回*/
318 printf("\nremonode(l,q), ");
319 print(*l);
320 printf("\nthe removed element:%c\n",q->data);
321
322
323 p=l->head;
324 for(i=1;i<=5;++i){
325 p=p->next;
326 }/*移动指针p使其指向链表中的第六个结点*/
327 printf("\np->data:%c, ",p->data);
328
329 s=makenode(temp++);
330 printf("s->data:%c",s->data);
331 insbefore(l,p,s);
332 /*将s指向的结点插入到p指向的结点之前*/
333 printf("\ninsbefore(l,p,s), ");
334 print(*l);
335
336
337 printf("\np->data:%c, ",p->data);
338 s=makenode(temp++);
339 printf("\ns->data:%c",s->data);
340 insafter(p,s);
341 /*将s指向的结点插入到p指向的结点之后*/
342 printf("\ninsafter(p,s),");
343 print(*l);
344
345 setcurelem(p,temp++);
346 /*将p指向的结点的数据项赋值为temp*/
347 printf("\np->data:%c, ",p->data);
348 printf("setcurelem(p,temp++),");
349 print(*l);
350
351 n=s;
352 printf("\ncurrent element:%c\n",getcurelem(n));
353 /*在printf函数中调用getcurelem函数,返回n指向的结点的值*/
354 printf("the listlinks'length:%d\n",listlength(*l));
355 /*在pringf函数中调用listlength函数,返回当前链表的元素个数*/
356
357 printf("priorpos(list,p):%c\n",priorpos(*l,p)->data);
358 /*返回p所指结点的直接前驱的位置*/
359
360 printf("\nnextpos(p):%c\n",nextpos(p)->data);
361 /*返回p所指结点的直接后继的位置*/
362
363 print(*l);
364 printf("\nthe element 'e' located at position %d\n",locatelem(*l,'e'));
365 /*返回l所指向的链表中元素值为e的结点的位置*/
366 printf("the element 'i' located at position %d\n",locatelem(*l,'i'));
367 /*返回l所指向的链表中元素值为e的结点的位置*/
368
369 p=locatepos(*l,6,p);
370 printf("the 6th element:%c",p->data);
371
372 if(!listraverse(*l))
373 printf("\nthere are all Lowercase letters\n");
374 /*判断l指向的链表中是否全都不是大写字母*/
375
376
377/*=========表间操作=========*/
378
379
380
381
382
383getch();
384}
385
386
387
2/*=======================================*/
3
4
5/*===============包含头文件以及类型定义==============*/
6#include <stdio.h>
7#include <malloc.h>
8#define NULL 0
9#define NODE_NUM 10
10
11
12typedef struct lnode{
13 char data;
14 struct lnode *next;
15}*link,*position;
16
17
18typedef struct{
19 link head,tail;
20 int len;
21}linklist;
22
23
24/*======================================================*/
25/*=======一些在其他函数定义中会调用的函数===============*/
26/*======================================================*/
27
28int compare(char a,char b){ /*---compare---比较两个元素的大小关系*/
29 return a-b;
30}
31
32
33int visit(link p){
34 if(p->data>=65&&p->data<=97)/*---visit---判断结点的元素是否为大写元素*/
35 return 1;
36 else
37 return 0;
38
39}
40
41
42int length(link s){ /*---length---求链的长度*/
43 int i=0;/*i不赋初值,编译错误“可能在i定义以前使用了它在length函数中”*/
44 link p=NULL;
45 p=s;
46 while(p->next!=NULL){
47 p=p->next;
48 i++;
49 }
50 return i;
51}
52
53
54void print(linklist l){ /*---print---在屏幕上输出链表的所有元素*/
55 link p=NULL;
56 p=l.head;
57 if(!p->next){
58 printf("\nThe linklist is empty.\n\n");
59 return ;
60 }
61 printf("The list:");
62 while(p){
63 printf("%c-",p->data);
64 p=p->next;
65 }
66}
67
68
69
70/*======================================================*/
71/*==========对带头结点的单链线性表进行操作的函数的定义==================*/
72/*======================================================*/
73
74position makenode(char e){ /*---分配由p指向的结点并赋值为e---*/
75 link p=NULL;
76 p=(link)malloc(sizeof(struct lnode));
77 /*---struct lnode 才能表示一个结构体类型并可用于分配空间的元素类型定义-*/
78 if(p){
79 p->data=e;
80 p->next=NULL;
81 }
82 else return;
83 return p;
84}
85
86
87void freenode(link p){ /*---释放p所指向的结点-*/
88 free(p);
89}
90
91
92
93int initlist(linklist *l){ /*---构造一个由l指向的空的线性表-*/
94 l->head=makenode('L');
95 l->head->next=NULL;/*不是l->head=NULL*/
96 l->tail=l->head;
97 l->len=0;
98 return 1;
99}
100
101
102position priorpos(linklist l,link p){ /*---返回p所指结点的直接前驱的位置-*/
103 link q;
104 q=l.head;
105 if(q->next==p) return 0;
106 while(q->next!=p) q=q->next;
107 return q;
108}
109
110
111int insfirst(linklist *l,link s){ /*---将s指向的结点插入线性链表的第一个结点之前-*/
112 s->next=l->head->next;
113 if(!l->head->next) l->tail=s;/*当向一个空的线性表执行该操作时*/
114 l->head->next=s;
115 l->len++;
116
117}
118
119
120int append(linklist *l,link s){ /*---将指针s所的一串结点链接在线性表L的最后一个结点-*/
121 link q;
122 q=l->head;
123 if(!l->tail){/*考虑到链表为空的情况*/
124 l->head->next=s;
125 while(q->next) q=q->next;/*尾结点的处理*/
126 l->tail=q;
127 }
128 l->tail->next=q=s;
129 while(q->next) q=q->next;/*不能忘了对尾结点的处理*/
130 l->tail=q;
131 l->len+=length(s);
132
133}
134
135position delfirst(linklist *l,link q){ /*---删除表中第一个结点并以q返回-*/
136 if(!l->head->next){
137 printf("\nThe linklist is empty,can not delete..\n");
138 return 0;
139 }
140 q=l->head->next;
141 l->head->next=l->head->next->next;
142 return q;
143}
144
145
146position remonode(linklist *l,link q){ /*---删除线性表l中的尾结点-*/
147 if(!l->tail){
148 printf("\nthe linklist is empty,can not remonde..\n");
149 return 0;
150 }
151 q=l->tail; /*用书上函数名remove时,编译错误“调用参数个数出错”*/
152 l->tail=priorpos(*l,q);
153 l->tail->next=NULL;
154 return q;
155}
156
157
158int insbefore(linklist *l,link p,link s){ /*---将s所指向结点插入在p所指结点之前-*/
159 link q;
160 q=priorpos(*l,p);
161 s->next=p;
162 q->next=s;
163}
164
165
166int insafter(link p,link s){ /*---将s所指向结点插入在p所指结点之后-*/
167 s->next=p->next;
168 p->next=s;
169}
170
171
172int setcurelem(link p,char e){ /*---用e更新p所指向的当前结点-*/
173 p->data=e;
174}
175
176
177char getcurelem(link p){ /*---返回p所指结点中元素的值-*/
178 return p->data;
179}
180
181
182int listempty(linklist l){ /*---若线性表为空表则返回1,否则返回0-*/
183 if(l.head==l.tail) return 1;
184 return 0;
185}
186
187
188int listlength(linklist l){ /*---返回线性表中元素个数-*/
189 return l.len;
190}
191
192
193position gethead(linklist l){ /*---返回线性表l中头结点的位置-*/
194 return l.head;
195}
196
197
198position getlast(linklist l){ /*-----返回线性表l中最后一个结点的位置-------*/
199 return l.tail;
200}
201
202
203position nextpos(link p){ /*-----返回p所指结点的直接后继的位置-------*/
204 link q;
205 q=p->next;
206 return q;
207}
208
209
210position locatepos(linklist l,int i,link p){ /*-----用p返回线性表l中第i个结点的位置,并返回ok-------*/
211 p=l.head;
212 if(i<=0||i>listlength(l)) return 0;
213 while(i){
214 p=p->next;
215 i--;
216 }
217 return p;
218}
219
220
221int locatelem(linklist l,char e){ /*----返回表中第一个与e满足一定函数关系的结点次序位置--------*/
222 int i=0;
223 link p;
224 p=l.head->next;
225 while(compare(p->data,e)&&p){
226 p=p->next;
227 ++i;
228 }
229 if(!p){/*考虑到查找不到指定元素的情况*/
230 printf("\nthere's no '%c' in this linklist.",e);
231 return 0;
232 }
233 return i;
234}
235
236
237int listraverse(linklist l){ /*----用一个函数遍历表中所有结点-------*/
238 link p;
239 p=l.head;
240 while(!visit(p)) p=p->next;
241 if(p!=l.tail) return 0;
242
243}
244
245
246
247
248
249int clearlist(linklist*l){ /*----?------将线性表l置为空表,并释放原链表的结点?*/
250 link p;
251 p=(*l).tail;
252 while(p!=(*l).head){
253 p=priorpos(*l,p);
254 freenode(p->next);
255 }
256 freenode((*l).head);
257
258}
259
260int destroylist(linklist *l){ /*----------销毁由l指向的线性表---------*/
261 link p;
262 p=(*l).tail;
263 while(p!=(*l).head){
264 p=priorpos(*l,p);
265 freenode(p->next);
266 }
267 freenode((*l).head);
268}
269
270
271
272
273
274/*=======================================================*/
275/*==================主函数部分===================*/
276/*=======================================================*/
277main(){
278 int i;
279 char temp='a';
280 linklist *l,*la=NULL,*lb,*lc=NULL;
281 link s,s_nodes,q,p,n;
282
283
284 initlist(l);
285 /*调用初始化函数,构造一个由l指向的线性链表*/
286 printf("l->head->data:%c ",l->head->data);
287 print(*l);
288
289 for(i=1;i<=5;i++){
290 s=makenode(temp++);/*每次插入结点都要重新分配空间,否则无限循环*/
291 insfirst(l,s);
292 /*将s指向的结点插入在以(*l).head为头结点的链表的第一个元素之前*/
293 }
294 printf("insfirst(l,s)*5, ");
295 print(*l);
296
297 s_nodes=s=makenode(temp++);/*_1_*/
298 printf("\ns_nodes:");
299 for(i=1;i<=NODE_NUM;i++){
300 s->next=makenode(temp++);/*_2_*/
301 printf("%c ",s->data);
302 s=s->next;
303 }/*构造了一串由s_nodes指向的链,并为其中的数据项赋值*/
304
305 append(l,s_nodes);
306 /*将由s_nodes指向的一串结点附加到l指向的链表的后面*/
307 printf("\nappend(l,s_nodes), ");
308 print(*l);
309
310 q=delfirst(l,q);/*---*/
311 /*删除以(*l).head为头结点的链表中的第一个结点并以q返回*/
312 printf("\ndelfirst(l,q), ");
313 print(*l);
314 printf("\nthe deleted element:%c",q->data);
315
316 q=remonode(l,q);
317 /*删除l指向的线性表的尾结点并以q返回*/
318 printf("\nremonode(l,q), ");
319 print(*l);
320 printf("\nthe removed element:%c\n",q->data);
321
322
323 p=l->head;
324 for(i=1;i<=5;++i){
325 p=p->next;
326 }/*移动指针p使其指向链表中的第六个结点*/
327 printf("\np->data:%c, ",p->data);
328
329 s=makenode(temp++);
330 printf("s->data:%c",s->data);
331 insbefore(l,p,s);
332 /*将s指向的结点插入到p指向的结点之前*/
333 printf("\ninsbefore(l,p,s), ");
334 print(*l);
335
336
337 printf("\np->data:%c, ",p->data);
338 s=makenode(temp++);
339 printf("\ns->data:%c",s->data);
340 insafter(p,s);
341 /*将s指向的结点插入到p指向的结点之后*/
342 printf("\ninsafter(p,s),");
343 print(*l);
344
345 setcurelem(p,temp++);
346 /*将p指向的结点的数据项赋值为temp*/
347 printf("\np->data:%c, ",p->data);
348 printf("setcurelem(p,temp++),");
349 print(*l);
350
351 n=s;
352 printf("\ncurrent element:%c\n",getcurelem(n));
353 /*在printf函数中调用getcurelem函数,返回n指向的结点的值*/
354 printf("the listlinks'length:%d\n",listlength(*l));
355 /*在pringf函数中调用listlength函数,返回当前链表的元素个数*/
356
357 printf("priorpos(list,p):%c\n",priorpos(*l,p)->data);
358 /*返回p所指结点的直接前驱的位置*/
359
360 printf("\nnextpos(p):%c\n",nextpos(p)->data);
361 /*返回p所指结点的直接后继的位置*/
362
363 print(*l);
364 printf("\nthe element 'e' located at position %d\n",locatelem(*l,'e'));
365 /*返回l所指向的链表中元素值为e的结点的位置*/
366 printf("the element 'i' located at position %d\n",locatelem(*l,'i'));
367 /*返回l所指向的链表中元素值为e的结点的位置*/
368
369 p=locatepos(*l,6,p);
370 printf("the 6th element:%c",p->data);
371
372 if(!listraverse(*l))
373 printf("\nthere are all Lowercase letters\n");
374 /*判断l指向的链表中是否全都不是大写字母*/
375
376
377/*=========表间操作=========*/
378
379
380
381
382
383getch();
384}
385
386
387