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