|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层)、Service(业务逻辑层)、Persistence(持久化层)的分离和耦合,一种面向过程的MVC的感觉。
9 q2 I3 ~9 r$ ^) \ 而这一切的基础就在于对链表的创建、删除、输出、写入文件、从文件读出......0 `+ O) ~, D. a# w: b& G0 a. ~
本篇文章在于巩固链表的基础知识(整理自《C语言程序设计教程--人民邮电出版社》第十章——指针与链表),只对链表的概念及增删改查作出探讨,欢迎指教。; X+ |0 n; k# t- v' Y* M
一、链表结构和静态/动态链表0 w6 T7 R/ c2 R) [. t
二、单链表的建立与遍历
+ e- Z6 Q3 x! v9 h8 W8 W, M7 ^9 V 三、单链表的插入与删除
, x+ G0 B U& E9 m) U. Z 四、双向链表的概念1 N0 I. q- c7 `" i
五、双向链表的建立与遍历
: ]- ]- A [6 f/ Q7 } 六、双向链表的元素查找
% T$ {, @, ^6 ?7 X7 K% A 七、循环链表的概念+ F9 u4 W! [; X |' R
八、合并两个链表的实例
, [( J" i% Q( m2 A8 l0 ^7 E. h9 r 九、链表实战8 ^: ^* k+ b$ Q) `+ c. R" Q) E# V
拓展思维、拉到最后去看看 (•̀ᴗ•́)و ̑̑0 Y7 p; L( @9 {
一、链表结构和静态/动态链表
4 s& G" W0 ?: `" u2 U 链表是一种常见的数据结构——与数组不同的是:. }, ]1 s! G" r! z7 K4 O% c
1.数组首先需要在定义时声明数组大小,如果像这个数组中加入的元素个数超过了数组的长度时,便不能正确保存所有内容;链表可以根据大小需要进行拓展。
\4 [% u, L2 G+ w3 b. f 2.其次数组是同一数据类型的元素集合,在内存中是按一定顺序连续排列存放的;链表常用malloc等函数动态随机分配空间,用指针相连。- a/ R5 D- e1 u1 ~. f; \! v1 _& t/ R
链表结构示意图如下所示:4 H8 C7 b- f" f# A0 I' _. \
u- J1 j5 O, Y9 k5 i7 u% _# |0 S8 S
在链表中,每一个元素包含两个部分;数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向NULL,表示指向的地址为空。整体用结构体来定义,指针部分定义为指向本结构体类型的指针类型。# L) h, G5 A- F1 S" Y
静态链表需要数组来实现,即把线性表的元素存放在数组中。数组单元存放链表结点,结点的链域指向下一个元素的位置,即下一个元素所在数组单元的下标。这些元素可能在物理上是连续存放的,也有可能是不连续的,它们之间通过逻辑关系来连接——这就要涉及到数组长度定义的问题,实现无法预知定义多大的数组,动态链表随即出现。
; d5 _7 h" ~# I 动态链表指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点的数据,并建立起前后相连的关系。
1 \+ X+ t8 W# H( g* n7 }0 q8 @! T& H 二、单链表的建立与遍历
; ~, [ `( q" w: Y9 M 单链表中,每个结点只有一个指针,所有结点都是单线联系,除了末为结点指针为空外,每个结点的指针都指向下一个结点,一环一环形成一条线性链。. M% |3 r5 ?6 a
链表的创建过程:
$ e% o i/ E$ c8 |* ~& |& G9 H+ Q ) | U0 X2 x$ J; a8 a5 E4 c. ]+ b- n
接下来在源码中建立并遍历输出一个单链表。4 G) \% M2 Y, b, y* C" z& ~
3 l* M3 q; M" u1 |" E k1 _8 v0 Q
6 P& I W0 t- ~) H
/ g2 [* B% D1 E" r- #include
- b; Z% Q4 O% s
( d9 j( o" q% U9 x* C- #include
! l4 h2 e- X# I
0 R$ g: X' N& v5 A- #include
+ C( x5 M: j, B+ R" { - $ q( T( ?0 v! s4 ^3 D9 O9 E
- /*单向链表*/
2 [+ j* h) t1 P' b - 9 C! k L8 |1 M$ {: q/ f
- struct Student/*建立学生信息结构体模型*/. i4 x; E$ J; S- v5 @5 S) v
( j- ]5 \+ e: Y3 I; k" M/ ~0 U6 g4 z- { u1 S" Z8 k+ P+ ^
/ V4 O9 r0 u U3 ]$ W8 ?- char cName[20];/*学生姓名*/1 S/ B- `. Y1 E' I6 _5 i
- 0 A+ t+ J, m* C3 V
- int iNumber;/*学生学号*/ O7 {. N# D, [: A% U2 E/ A% a5 C
- * T. i2 b |4 [ R4 `1 o1 F1 w3 {: e
- struct student *next;/*指向本结构体类型的指针类型*/3 I: T1 a: o6 w. q( f6 k* B. c7 y
- / D( O/ l# h- t) m5 r
- };5 ~( Y3 W" a, e! b
% L- u. ~) _ {/ ?- int iCount;/*全局变量表示链表长度*/
$ E+ a% K+ ^$ j, F$ G4 d" u - 7 W& x7 N* s4 _
- struct Student *Create();/*创建链表函数声明*/
0 m L* I) O. a
" K4 M9 l$ v' r. ], T" O3 `& J- void print(struct Student *);/*遍历输出链表函数声明*/( i k; C1 i- z4 q
. u; ?+ ]) n/ C/ y2 ?- int main()
+ }/ ?# P, ?' z7 N - " ^3 B: X8 y! q h* E
- {
! _; ^' {# K" r3 o6 t0 }( U
/ }# J8 ?, ]* X- {! i! l- int insert_n=2;/*定义并初始化要插入的结点号*/
! y$ ^; {1 p: x# A" `, i
2 ?# `( h+ c( S- int delete_n=2;/*定义并初始化要删除的结点号*/
q4 P7 O7 ?+ ~5 U2 f
/ }. k, J# |" n6 v( \- struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/4 l0 I1 w, E$ x
- . d0 F4 ]% y# f2 Y/ `! d$ j8 K
- pHead=Create();/*创建链表,返回链表的头指针给pHead*/
4 ~! f. G) C6 L+ f
' w- X1 N. Q& ~! e- print(pHead);/*将指针pHead传入输出函数遍历输出*/
- s3 s( L8 M" Z. A& z - ! i8 h. H# T4 T" F( X. b
- return 0;0 ^/ y7 l$ N9 P6 x$ {- J
- R$ Q, s& S: y, C2 a- }2 f& {* k' g/ r
- . ^' W+ P* h: M: _
- struct Student *Create()1 L: q" R' G( R
- & `* H* E3 U+ L% Y
- {
4 U+ d! c; d& m! Q6 G B) B* V$ l - ) p5 ]: _! C0 J. h! J
- struct Student *pHead=NULL;/*初始化链表,头指针为空*/
9 g# a/ l f% A" k5 z9 g - + F3 I7 V! {+ D, ]& \0 z, n1 ]- E
- struct Student *pEnd,*pNew;9 _ K; n' a% ?. |' ]2 K* F
8 j& N% I0 T9 x. a1 S) S# n3 ]+ v- iCount=0;/*初始化链表长度*/' g+ F, I8 B$ u) m
- & ?# d* z+ W/ ^( C; I7 S5 f
- pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*// h5 \& I5 q; {% ?7 N' e
% x) J6 M: [+ ~- scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
! J# ~5 e; j. i: X* M4 D/ g - % D, V+ I8 E( n; z
- scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/
2 X( h: e y7 e1 U8 l& } |
& i: E6 O" N# \ Z- W4 v) L& R- while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/ i* I1 Z; l$ H4 s0 ~
- 2 W; Y( V2 |* m+ K3 Q7 n$ x5 m( G+ v
- {
: W" T: `5 r2 c9 r) u
0 r* g6 Q3 U8 G9 v+ K/ ^% z w0 m- iCount++;/*链表长度+1,即学生信息个数+1*/9 \; z8 s+ [- Q, t% Y8 e
/ | I, k. Z2 O- if(iCount==1)/*如果链表长度刚刚加为1,执行*/2 g/ [" Y" a) d7 c7 ]/ E5 g
- u: o, r4 v% D& Z1 P1 [- {5 W- F% v7 X' Z- L/ j9 s
4 W6 @- H4 x& E# g) A1 D* i- pNew->next=pHead;/*使指针指向为空*/
) g% G' J. ~8 E* u - $ F. T, ^. q; g a+ ~0 E- Y. S
- pEnd=pNew;/*跟踪新加入的结点*// P& t7 P4 f- y# K
# x4 V/ U- v' ~* \- pHead=pNew;/*头结点指向首结点*/
' X$ Y% p D/ @1 s/ k5 ?
% Q6 p" R0 a$ _3 }- }
: n+ n9 U; d( y- s* K# e' z, e8 V - 1 X/ f9 C! b; `( x9 F" _
- else/*如果链表已经建立,长度大于等于2时,执行*/
- d, B, v+ |5 w3 ~) J
5 P( [; ~3 j0 U- ~4 A! R" B! B, ?- {
: _. X2 r% o& @* \: Y' n4 d - , X; W9 l6 b. s; Q+ M, B# `
- pNew->next=NULL;/*新结点的指针为空*/
" K/ i% k( i; F2 z1 B9 M" W( M+ e - ; q2 @. b/ w( m; r% |
- pEnd->next=pNew;/*原来的结点指向新结点*/
( j& R' K' M* ~: L
+ |1 P w9 I: n3 y$ u% M- pEnd=pNew;/*pEnd指向新结点*/" ]. G1 C, |' G3 e2 w& t' i
- + }1 z/ O* o) e0 }+ ^8 C7 }5 S
- }
8 [0 G3 s/ _. u) y5 ]+ B7 M* ?
; _* H7 j4 X: b" `- pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/& v; @# {7 O- K. N* H
1 t: ~/ X1 t& |( |# G/ Y# J4 Z- scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
' k* |8 X, k: \% m- J+ d
k1 \. D+ O S: x' y3 i- scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/8 |" T+ \8 R. i
) Z) I: ]# K. O! {! S; G- }
3 F/ F" z" y+ [0 M; V: g: Z - ; t. t6 E- I" `3 J& n0 h
- free(pNew);/*释放结点空间*/
8 i" X' z4 l$ n! [
* A/ C- [8 P+ k( f) p, P9 g+ W- return pHead;/*返回创建出的头指针*/# Y x+ ^8 F) i( R9 T5 C
- : w1 M2 t& U: W1 J/ v
- }( u/ t$ b- i) h3 E
2 T. [$ M: ]# W- void print(struct Student *pHead)) r" ^6 m3 x$ V, l5 ?; K$ T- X: c4 j
- ; V) h @- \; @! {
- {" w/ S, j" J3 J# T
- $ N) @0 q8 M; ?
- struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/
m/ q# w- L# e" H) y
( p% H3 C) `2 J; d3 A. T- Y J- int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/
3 E1 ]9 b' q# M9 ~3 N3 V" l
$ U0 ^* k: X9 {( d- r& n0 t& F- printf("总共%d个学生(信息):\n",iCount);( i# i1 X" n( U) K4 X. J- u8 ?
- + v, H0 I R7 b* J6 {' {
- pTemp=pHead;/*指针得到首结点的地址*/7 y1 k% v# J% ?8 m! H
- " K+ _, [: S2 H1 o$ ?" R
- while(pTemp!=NULL)/*当临时指针不指向NULL时*/6 I( S3 _& N0 x( s! }3 x$ F
- 4 \) {/ |; ]4 e: i
- {/ n; g: Q. ~6 r1 k9 M: G1 \
- 7 \9 \: P X) P7 @% _
- printf("第%d个学生信息:\n",iIndex);8 ~/ _( O- @8 T
- 4 H6 ?/ T+ g0 ^6 }* z
- printf("姓名:%s",pTemp->cName); /*输出姓名*/! y& x2 j3 Z, D! ^6 e
/ h/ ?, a) _: Z0 {# J9 k: n9 s; y- printf("学号:%d",pTemp->iNumber);/*输出学号*/
; D$ ~& w4 ?% }) k. j - : m) F7 u: d/ ?/ z( K) D
- pTemp=pTemp->next;/*移动临时指针到下一个结点*/
A& U# x5 B! Q
" C5 C9 @9 B7 S( F- iIndex++;/*进行自加运算*/
' S6 n2 u" i( c/ l2 u4 f7 ~# k7 i& _
: _8 K2 h# [- Z7 U9 X- }
! s, F( G+ _, G" T9 q. ?( A - 5 l% I# d! N2 T! P4 G0 T
- }
复制代码
* C" Y) x5 ^- T- V% |) L' @1 F& e; m7 W/ r
& d4 u5 g( J1 Z, U8 f: Q
, m5 C+ E- B$ G1 N1 z! E
三、单链表的插入与删除. g: w1 U) `. P3 o& r& c- R5 v
在本实例中,插入时根据传递来的学号,插入到其后。
- x" U* k$ K+ I* i b. d 删除时根据其所在链表的位置,删除并释放该空间。$ j, i, G6 S( ^6 X
主函数增加如下:
5 C& \/ B! Q+ Y" i% s
! \4 T% m, J+ }3 C! F! w: K
) Q8 \8 u7 Y4 Y7 Q1 ^5 B8 N7 W1 W: F7 x4 ^2 X- U$ S
- int main()
# E6 q, G" Q( o0 M - & |* R! C, Z: k# F# `
- {
* K* g6 d$ @& c/ R. c
0 \- A8 p, v8 G; V* Y- int insert_n=2;/*定义并初始化要插入的结点号*/7 n. M Z# Z4 v" K; U
% r6 F: F4 i3 D+ J# q, x/ C- int delete_n=2;/*定义并初始化要删除的结点号*/
7 N% U$ X- w; R% q - 1 T2 I/ j1 S* x. w. _
- struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/4 ?$ J* ]- X: w- v0 ^- `
- / {4 N( o, f5 l3 j, \6 x b* P
- pHead=Create();/*创建链表,返回链表的头指针给pHead*/
- I+ M. v' U# S G- ]* w - " d R. e8 E) ^+ L
- pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/' Q4 U( N' K6 F0 T
, p* \7 V- H% R; \ ~3 u# X- print(pHead);/*将指针pHead传入输出函数遍历输出*/" N1 i4 U. i" M
9 a4 d9 L3 `0 {1 i- Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/
1 C; Q: K: @6 U% `- L - 3 Z( u8 h& }2 T4 {" L# D
- print(pHead);/*将指针pHead传入输出函数遍历输出*/4 K% t1 P, l9 ]3 K4 y/ q' ]. f) D! P, A" f
- & L6 Q7 F/ k c
- return 0;
$ l6 E$ ?4 Z/ J* L0 J - " a3 }! _7 K/ V# b" A, u
- }
复制代码 * Q. e% N! A" Q: e$ C
. J+ J7 N- h! n2 c! a4 S/ n+ e# ^6 Y& O8 u" d/ d
/ h# }* F% W& G; x# W 插入函数:+ o' y' b8 I/ p8 x
" f% c7 W: e8 v* X* h6 i
$ V/ t+ U+ I+ T
" M4 N$ S X, ]; y; [1 M- struct Student *Insert(struct Student *pHead,int number)
3 T1 e0 {7 A5 r4 ?! ~' p
$ O3 e, L2 ~# q0 L# D( W- {
$ S8 C9 h% Y/ U+ ~5 F+ ]9 ~
0 J9 h5 }! c# i. t- struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/
" i& j& X) Q5 D+ M+ d - * r5 d Z0 B3 y6 m$ f6 C+ P
- while(p&&p->iNumber!=number)
* s4 t7 Y! ~+ b# Z& x - k1 ?% ]8 c% V* f# S2 a
- p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/- k7 Z% F* B$ ^' T: U, W, o" k
! k% B% x( F- |8 V+ K0 z9 r/ T' t# I- printf("姓名和学号:\n");
; \, l0 A3 H l! @) D3 Q; L
4 r3 n8 _1 M0 u. p- /*分配内存空间,返回该内存空间的地址*/2 D6 V7 A* _( v0 L* V, ]3 a
) ?% D2 E( K' ?0 W( J1 [7 g- pNew=(struct Student *)malloc(sizeof(struct Student));
1 K7 Q2 \) f8 K. E - % r. o' v: p" k
- scanf("%s",pNew->cName);
9 Q4 A/ c# q3 C* I8 Z( C6 n - & z" {5 L" p! ] l; H3 W0 d! V8 [
- scanf("%d",&pNew->iNumber);
1 o, Z' z9 w/ o p
( h ^' q& X5 f7 X- pNew->next=p->next;/*新结点指针指向原来的结点*/
" y- Z4 b2 S8 a0 I
1 T \/ t* U. X2 [- p->next=pNew;/*头指针指向新结点*/
3 q) | I& t- Q7 F- @5 J
0 Y6 r% I0 H# U: E* J1 X- iCount++;/*增加链表结点数量*/
! t5 O W7 G, T - 8 H, F+ W# D! V
- return pHead;/*返回头指针*/4 Z# j" n3 Q: S5 l- r* ~2 f9 M8 B
- 7 I: r" {& ?8 y& K/ \
- }
复制代码 2 _! H! v7 V# X2 Y0 x
: N. D9 c% P7 N
$ M# l1 P4 ~7 f; v
0 _* A, G3 l% I) V J$ V' E8 l ] 删除函数:
/ l( d5 g( t% Y8 T1 ?5 e7 A
" ^, G7 x! L' Z i
8 A3 c+ E0 y C, y3 k- K$ v% ]+ ?1 V) h, y: e: i+ s
3 d/ p2 I' | U j, b
- void Delete(struct Student *pHead,int number)
% ?& j" Y7 n4 m# D# m. y2 e - # V1 Z+ y# P& n/ M' i
- {* A& P" q# L; Z$ v2 F4 g, P3 _4 r
( k5 g* B; ]% a" C- ]8 {- int i;4 R( }2 G4 d% E% g% Y/ U
* f6 y( T4 e# P& |9 C- struct Student *pTemp;/*临时指针*/& f+ N+ x- Z1 p4 f4 y4 y: K
$ f( Y: @- u$ }' K& B- struct Student *pPre;/*表示要删除结点前的结点*/+ t: x( g% `+ `+ { s
# h; S* t4 i' t8 m3 d, x- pTemp=pHead;/*得到链表的头结点*/: Z8 p) c$ N* Q1 P: Y3 o/ O' H
- {' W( ]2 l4 r' d; n0 }
- pPre=pTemp;
1 T# `/ ^6 D$ d% e- N- {+ S9 [
; V2 A A) h% U- for(i=0;i
) o7 [7 G% v& x4 x2 L7 ` - J9 c1 M; j7 Z
- {/*通过for循环使得Temp指向要删除的结点*/
0 [0 `$ W- W' g& D - 6 s7 L9 G4 Q. Y0 T- j5 n: O
- pPre=pTemp;
: U0 N- T4 X5 I - 9 y+ p' v2 N5 I8 t; Q
- pTemp=pTemp->next;
# ?' @$ ~0 c m. T
* `: T6 T) T& k0 }: d- }4 J* {$ }) J" K, C; j' ^
0 S" z1 I7 d" W+ X7 t# w {- ?- pPre->next=pTemp->next;/*连接删除结点两边的结点*/
: M$ N0 L' x1 Z+ q' l X" b - * _8 B5 `/ a, v# p
- free(pTemp);/*释放要删除结点的内存空间*/
# a. y6 _, x% H& k; D - 8 K4 E6 Q/ p9 d0 |3 `2 y
- iCount--;/*减少链表中的结点个数*/
. L' [, }; P" X5 K4 \, o/ G( h
( K! f0 d9 ~5 [% N- O3 ~/ h& {- }
复制代码
$ B/ I# Y5 T! A+ B1 d
6 s4 W. i4 Z$ C5 N, @4 c![]()
3 [9 D' S4 E0 i$ k D5 @ 四、双向链表的概念
4 d0 k6 ~+ i- K. M 双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。
9 d5 P3 ?7 Q2 f1 F 在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。" p' E, D5 `6 D! b2 r" Q% a
双向链表结构示意图:% v) u+ X2 U2 _7 h( P
# ^7 Q) B: n. C. |$ Z / U, f9 [" K; O+ w# ~% ^
" ]4 V8 q5 U& P1 ~2 X: d
五、双向链表的建立与遍历4 Y6 ] `0 d) B3 Z% i8 t5 C
双向链表的源码实战和单链表类似,只是多了第二个指针域的控制,这里直接贴上没有注释的源代码。 F+ Z# C" f1 z4 I
O9 s: p% a4 u' g1 L/ m
7 Q. m: N+ X( c/ d
" K6 e1 e# `% s/ ^* X- #include #include
# N" [. ^; n. o
/ \5 j( m0 t" x3 d- K; w( E; l- #include
5 O, s( L3 t E6 g8 V2 G - 8 {1 n/ B" h5 D( Y4 p4 \" n1 K) j6 B
- #define N 10
# Y$ Q3 B) O+ R% B
3 c z+ x3 e$ N& X- typedef struct Node
8 ~ ~; u/ C: Y7 i9 i$ W
' `9 q9 m! o4 s' G3 V0 E+ U, g- {
. s& H5 Y: ]' C! ]( Y! I - % L* {5 O- O* v D3 r- o$ i
- char name[20];
) q5 {8 {! v$ k; y - 1 Y a" f' }& x/ A0 H$ ^& k
- struct Node *llink,*rlink;
: l$ _' g$ O: V9 _% q - 8 Y/ \5 `0 Q5 H
- }STUD;
7 H8 |2 c& H% h& p' F' \8 `1 W, g - 6 \8 g, N- B) a' e& F8 ?5 w
- STUD *creat(int);void print(STUD *);
' L3 l& G, {. c) k1 N* |
E# _3 ?; f, l. a+ B9 P. x- int main()
- t% B+ h" D8 H5 Y
* y8 j) ^* J1 n* V5 [0 L/ ~" h- {5 ?# Z# E0 l j: I
- 4 C; B/ {4 h" l2 f, F" }
- int number;4 e! z5 v$ Y& M6 ?- j8 ^
0 J6 [* J0 e" d h2 p/ Z- char studname[20];
% D# R4 W4 J8 V8 v. ~* Q! p - ! W8 r) Y! W4 a
- STUD *head,*searchpoint;2 f ~& o. ?, ~
+ { u1 `9 |3 \% ~; j- number=N;2 n9 N% K" z0 y5 G7 Z: F
- ' B0 t' k g/ L2 O3 Y" @ v
- head=creat(number);
( R5 G2 k$ q0 X5 d8 I/ F w/ U - ; U$ o+ e4 a) [$ B7 y! R2 D
- print(head);$ f4 ]$ A: q+ O9 C. e
- T8 I4 H1 Z3 Z* u' K& W- printf("请输入你要查找的人的姓名:");
( ?+ S$ ?5 A5 {) m* b& ~
( V* h# s' r% C: H- scanf("%s",studname);
* v1 C# V. ?3 O# _8 f5 `- u
1 n6 k0 q% v, f- searchpoint=search(head,studname);
+ m# z" N* v* P; X- |" Z$ d - 2 ^$ {2 U1 a& Y
- printf("你所要查找的人的姓名是:%s",*&searchpoint->name);
% n9 S0 L. _3 l
6 V: r: U1 `: E- d+ n# j7 J0 U9 K- return 0;
; P* j/ q, g% c* t
! \$ E5 K' @) t9 t8 q6 Q8 r4 T- }2 U7 c0 M$ ]2 t8 t+ s1 E
- : Q; w/ e8 [6 @+ |( u4 o3 J
- STUD *creat(int n)
. l. j' N! ^3 |. G* h
9 X, K# q4 ^" D) n8 i- {
. r( E2 r% c7 K' o* g
X" E1 t4 ?. y) U3 r6 X% A- STUD *p,*h,*s;+ `; ]5 u5 Q3 m: s
% w" c! U/ ] q; b& v9 @- int i;8 p6 D% l7 n" v7 y+ H7 J
- 6 }, Q5 d" v/ s. g% E
- if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
8 c5 _/ d; ]- Y7 M9 q, k6 ~- K/ g: W/ [ - % I. {4 {0 |6 `1 p- F/ @* I
- {9 w! a; H) b* m; Y& ~
% U( t L1 k6 w6 a- printf("不能分配内存空间");
: T" ?+ Z6 r1 i W8 Q! r
: q0 c0 @' S: l C- exit(0);
& |! \* A9 _9 u0 V- ] - # o! k8 `2 {9 m1 D* j7 ^
- }
5 Z' t: l0 ^: C& ~
2 x9 i1 c m. A, L6 C+ t- h->name[0]='\0';3 Z9 j1 D' ?9 a- X' a+ }3 W
- 7 F/ d9 ]' [ U4 P0 [$ [0 F
- h->llink=NULL;
: K& i( P- P' e! Z. d$ _" `/ r
1 V: L: S1 S4 t- w: d/ u0 T1 o- h->rlink=NULL;
( l8 \0 v! U8 G& L& w1 r5 d
' i( I: C3 O( u1 e r4 x. {- p=h;6 d% P7 E' A( Y0 d5 [) c
- - T! h8 X& Q) {
- for(i=0;i
7 J) g7 e2 D" G
2 v( m3 p2 `+ n' S3 ^0 l4 d- {" k/ a' T# I1 \6 D: ]' y% H5 L* S
+ u5 h, K1 p$ t7 Y, [1 n" O" [# P, _- if((s=(STUD *)malloc(sizeof(STUD)))==NULL)% q4 r9 ~" z( V% l# c! }0 y; p9 l
; F% G4 @) v2 a- {1 B1 ^) w. t4 w. ~# K1 n
- ; I( {0 J N" Z
- printf("不能分配内存空间");
+ L3 F" o* J, j, W
% @6 n7 _! W4 l6 x: S! ?. [- exit(0);
7 y! s, B# h! X9 V - / r. S0 Q. t, [6 S. l
- }
4 D3 j/ [6 y" z( f7 Y! A0 V0 D
5 e" e# X) ?! }, ?5 x- u- p->rlink=s;
/ k) X' L: K& c# T( y+ s
7 W; p, L& Z) Q m$ G' x- printf("请输入第%d个人的姓名",i+1);
+ u3 p1 G: o0 t+ h9 T7 X9 x
9 t# M2 k0 n2 _1 ~- scanf("%s",s->name);" w. S0 z% n' f: o' n
3 p" U8 G! Y$ }8 I: x9 l5 a0 a- s->llink=p;3 M4 r7 W- P+ E' g$ o: v5 Q
- ; k$ Z: D I0 d3 M
- s->rlink=NULL;; v, C3 h0 Q5 x7 ~# T
9 K" U+ x2 E8 h2 t' `" Q: `- p=s;
0 W' M' j; c0 ?/ J$ \ - * a! Q* j2 E! p0 e1 d5 R# G! Z
- }' a/ v9 G1 [* G, K, v
! h& G. T& F9 Y# F% C( ]2 d$ V- h->llink=s;+ |8 w3 A9 f7 i$ G% c: f
) Y$ `. U" \+ _. o: X1 S# q- ]2 Q3 t- n- p->rlink=h;3 f& @7 x& v8 U2 D9 ^) x
- - d3 i' G6 e3 f! |" d& `
- return(h);* ?# \/ Y! H( @5 f# b* Q5 e" C
- @& \1 b( p* Z! o6 S- }void print(STUD *h)
+ ~$ z5 W5 H, e- p7 m' h - 4 t0 Z; G) x0 U2 V+ ~" h! p6 t
- {& r: c. O# I! v2 U' ^- c- y
) w! e7 F3 A ^- u1 F- int n; g: j/ ?9 ^8 V0 T; i8 S5 V3 t1 n( Q
' L7 g5 ~6 F* R' A- STUD *p;$ H1 W- M* B8 f# Y( y
- ( Z9 D, s Q! J- ~- C2 j7 M- f, |
- p=h->rlink;0 X) E( R! `+ \- b# y
+ b0 U5 H K- J5 A: M- printf("数据信息为:\n");
% M' [% W9 z" K- M7 a: x: }+ w' d
# T% S- t+ |$ T* e- V, H w2 u% a- while(p!=h)4 {7 b R2 S. Y
- 1 W# U0 s% S7 u' g- ]7 \
- {$ L- k8 M: z' o5 E
- & h3 F' }8 ?% X1 i1 R' j, ?
- printf("%s ",&*(p->name));& `- h+ R" `$ t& a. } Z
) U+ V! E& i& t6 K- p=p->rlink;( r( p, F# V2 c: y( D- m: _: } Q, X
, g% s) z0 ~% u7 y- }
5 L8 M! d* l- G: Y9 ~ ?: v - 6 D/ a! `" s. e% n4 j
- printf("\n");
' ` b* L4 h4 t+ T - 2 F# N3 D: W' Y0 f( a6 l: U/ X
- }
复制代码 5 V# b6 T/ A; e2 i0 n
: U. {- _( J3 q0 }& s' x2 J
" G1 {& c" W, P/ Z" X1 g- N. @
$ P2 k$ c* B- F7 f6 \- [5 L
六、双向链表的元素查找/ R0 M7 E4 `* c) }. b8 N5 i
查找函数 STUD *search(STUD *,char *);
1 D5 v. S7 O9 k0 z c; |. T
& a/ ~4 j7 E8 f( P. t R. P# ?2 j1 r2 T: |) K/ O! Y
2 g+ V/ O% U2 m( b0 g0 G! Z1 [6 m- STUD *search(STUD *h,char *x)
" G0 c5 j6 `3 k2 g" X8 ^
0 B5 k) N/ \7 s% i# P5 I- {' b' D; T* F4 y% k4 d
" q U- g( O) n- h3 w' z+ o) U- STUD *p;; _$ Q4 _, B% q- w
- $ ^: D1 N# X1 d. ?/ f+ U4 p& d
- char *y;: O1 O) v. X& ^9 D% R
- / A0 W" W% b$ d9 Y# g* v, F
- p=h->rlink;
8 m+ M% G! c. R% a1 F. H: t5 @
' S% X% ]9 Q3 h6 i6 ?- while(p!=h)
- s, c( y v& A - ! k2 S3 m7 e) G( B1 w
- {' _1 a$ v' |& ]4 t
- * c: R% q% u& {( w
- y=p->name;
% R. H; D' M& t
8 W u6 @9 b/ B" O3 x" ?9 ^0 Q- if(strcmp(y,x)==0)
& U6 D9 M: j1 u
9 z. X0 r7 L" Z# T- return(p);
: x$ A0 n5 T: W! ?' Z( u% m
" r* d0 {! F) ~: a$ I- else7 b' s+ v1 ^" a8 O' f
- 6 U% i: `3 V7 h' q
- p=p->rlink;& f; o) p1 `" u7 W! f5 E( h
, p$ i$ z* e* s3 a* q) l/ A- }7 I: c6 G1 x4 x6 u0 S% H/ H
" d- k: i# S* n6 }- printf("没有查到该数据!");
9 a0 X' m1 d/ P8 S) \
( w7 \& l s% e3 ?- }
复制代码 & \, p: J1 Z: ?( [' C
; W3 Y5 M% u9 G1 `) Y& \
% V, u3 K' K9 I/ u7 N @
% z) p3 @! V9 k8 B 七、循环链表的概念: K: h8 O- ^3 B: d/ C
类似于单链表,循环链表也是一种链式的存储结构,由单链表演化而来。# f2 @/ I$ O0 S
单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。- S3 \1 W9 [* M. ~
这样头尾相连,形成了一个环形的数据链。
$ P( m6 o5 F4 E6 ~+ G+ |' a 循环链表的建立不需要专门的头结点。
( [/ K: J8 w' r0 `9 i% {( l i 判断循环链表是否为尾结点时,只需判断该节点的指针域是否指向链表头节点。& z7 p" b/ I. V% A" } M, g
八、合并两个链表的实例
4 P% M* c: n, \( {6 P# A4 C& Z 建立两个带头节点的学生链表,每个节点包含学号、姓名和成绩,链表都按学号升序排列,将它们合并为一个链表仍按学号升序排列。1 z# m' s/ J* D: s! i# O
算法分析:5 w( |4 I L- Z4 E$ T$ n4 P. ]+ z3 |$ s
合并链表用merge()函数实现。函数中定义3个工作指针a、b、c,其中a、b分别指向La链表、Lb链表的当前结点,C指向合并后的链表尾结点。合并后链表的头结点共用La链表的头结点。
/ M5 z) c3 x# J c6 u* j ①合并前,先让a和b分别指向两个链表的第一个结点,c指向La链表的头结点。
0 q5 y7 F% Z- X: X: B/ S ②合并时应该分3种情况讨论,即La和Lb都没有处理完;La没处理完,但Lb处理完毕;Lb没处理完,但La处理完毕。
4 ^) J; k4 R6 h ③合并过程中应始终将La和Lb链表中较小的一个链接在Lc中,方能保持有序。
H% n7 A8 |3 g5 O b; h: y% ]2 u! G" m" Y" F) }
! U. W: v3 A* T' X \5 ~; u% u! @
H; A: c" {1 M/ F7 d r% R2 J$ Z& v/ k% ~+ J
- void merge(struct stud *La,struct stud *Lb)% ?- Z3 f- }! D$ r2 V, X! Q
) {5 w3 }9 k" o- {
( e3 t4 p5 A1 n9 k% y
6 V( x+ [9 P( T1 n0 Q% L7 o. s4 U- struct stud *a,*b,*c;
# S5 j4 k' c$ t4 r7 J
, \) C3 A6 W! f% D5 u- c=La;
2 a& M. T1 P: g9 x7 n* x0 ~: z6 s - " k7 Z1 R0 t A" `" l" d+ h& r
- a=La->next;/* 合并前 */
( R# ?" _0 f0 M2 Q( [ - . h ?- V! N, }
- b=Lb->next;; W2 E9 t t( V! C
- 2 u! N& o; l) X+ `4 w
- while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
6 D% T7 f1 w3 L
) m7 b3 Z3 H" i5 M. }9 o5 K; l6 U- {. L& v+ W% z% G, A* Z
- - W+ l0 S$ ?$ Q+ |- P: [
- if(a->num <= b->num); W7 `8 Q! `! i, N6 u9 l$ J' \
- 3 _, K8 O/ u6 M8 N0 u- e# Y8 L
- {7 U! t* a' P; p) p* M& m* S- i9 E
9 y! O% ^* F0 V; X) H0 e; e+ V- c->next=a;# P7 z8 w$ A4 v: B
- 7 }- G0 `( I0 q$ Y" C- ?
- c=a;! M# {" V, p, I: M" p j& @
- 0 o. N# z/ K5 f4 r0 b
- a=a->next;6 `0 \4 P: `- D
! u) [1 D5 i& O5 ? y5 v- }2 [% J7 L" \ h
- $ ]$ z6 B+ x& H& ]" Y- o3 }
- else z9 X) {* U; {8 M
- . t6 j; K9 U7 \" ]1 R
- {
9 f4 }8 y1 z' }: _
}0 n5 h8 u' d( e- c->next=b;6 b2 V: p3 D% X' i) E' h
o! u6 O9 } v" q" L; C( o6 p- c=b;8 }+ c+ N1 A2 W2 m
- $ A7 ]- _( m+ C5 k! L& W0 K
- b=b->next;
/ ^7 k/ _2 O5 k
S% a- R! g& L, F* \- }
! q7 g& w, F5 ~+ y: r - % S5 J0 v+ r9 h( M* \' m' P
- }
" z6 D' ?% R% b$ M# Z
4 m ^+ ]' m0 d/ k2 x2 }1 S- if(a!=NULL)8 Q, D* C7 j9 K, l* k
- 4 ` E1 O K/ B, {4 q4 P- g3 k
- c->next=a;/* 若La没有处理完 */1 ]. k2 T' `2 J) q* M
0 P* {4 w9 r- J" W4 N& W- else
6 v9 g# j0 w0 j( S6 d
2 T5 V2 q5 Z; U. q0 l7 M8 T; x+ z6 a- c->next=b;/* 若Lb没有处理完 */
p# K: Q- D" S+ C - 4 b. m9 c( s/ G ?3 M4 B: A
- free(Lb); /* 释放Lb的头结点 */
( y* A6 b+ e+ M* A% e4 b
; c/ C2 [4 \( i% w2 G- }
复制代码 1 {7 f3 \- N4 z. f8 j m
/ V: z3 t) S; q- ~2 o
0 i2 k0 d+ z; p; w4 z
|
|