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