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