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