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