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