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