找回密码
 注册
查看: 704|回复: 0
打印 上一主题 下一主题

玩转C语言链表,单链表/双向链表的建立/遍历/插入/删除

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-9-2 17:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
  最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层)、Service(业务逻辑层)、Persistence(持久化层)的分离和耦合,一种面向过程的MVC的感觉。
9 q2 I3 ~9 r$ ^) \  而这一切的基础就在于对链表的创建、删除、输出、写入文件、从文件读出......0 `+ O) ~, D. a# w: b& G0 a. ~
  本篇文章在于巩固链表的基础知识(整理自《C语言程序设计教程--人民邮电出版社》第十章——指针与链表),只对链表的概念及增删改查作出探讨,欢迎指教。; X+ |0 n; k# t- v' Y* M
  一、链表结构和静态/动态链表0 w6 T7 R/ c2 R) [. t
  二、单链表的建立与遍历
+ e- Z6 Q3 x! v9 h8 W8 W, M7 ^9 V  三、单链表的插入与删除
, x+ G0 B  U& E9 m) U. Z  四、双向链表的概念1 N0 I. q- c7 `" i
  五、双向链表的建立与遍历
: ]- ]- A  [6 f/ Q7 }  六、双向链表的元素查找
% T$ {, @, ^6 ?7 X7 K% A  七、循环链表的概念+ F9 u4 W! [; X  |' R
  八、合并两个链表的实例
, [( J" i% Q( m2 A8 l0 ^7 E. h9 r  九、链表实战8 ^: ^* k+ b$ Q) `+ c. R" Q) E# V
  拓展思维、拉到最后去看看 (•̀ᴗ•́)و ̑̑0 Y7 p; L( @9 {
  一、链表结构和静态/动态链表
4 s& G" W0 ?: `" u2 U  链表是一种常见的数据结构——与数组不同的是:. }, ]1 s! G" r! z7 K4 O% c
  1.数组首先需要在定义时声明数组大小,如果像这个数组中加入的元素个数超过了数组的长度时,便不能正确保存所有内容;链表可以根据大小需要进行拓展。
  \4 [% u, L2 G+ w3 b. f  2.其次数组是同一数据类型的元素集合,在内存中是按一定顺序连续排列存放的;链表常用malloc等函数动态随机分配空间,用指针相连。- a/ R5 D- e1 u1 ~. f; \! v1 _& t/ R
  链表结构示意图如下所示:4 H8 C7 b- f" f# A0 I' _. \
  
  u- J1 j5 O, Y9 k5 i7 u% _# |0 S8 S
  在链表中,每一个元素包含两个部分;数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向NULL,表示指向的地址为空。整体用结构体来定义,指针部分定义为指向本结构体类型的指针类型。# L) h, G5 A- F1 S" Y
  静态链表需要数组来实现,即把线性表的元素存放在数组中。数组单元存放链表结点,结点的链域指向下一个元素的位置,即下一个元素所在数组单元的下标。这些元素可能在物理上是连续存放的,也有可能是不连续的,它们之间通过逻辑关系来连接——这就要涉及到数组长度定义的问题,实现无法预知定义多大的数组,动态链表随即出现。
; d5 _7 h" ~# I  动态链表指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点的数据,并建立起前后相连的关系。
1 \+ X+ t8 W# H( g* n7 }0 q8 @! T& H  二、单链表的建立与遍历
; ~, [  `( q" w: Y9 M  单链表中,每个结点只有一个指针,所有结点都是单线联系,除了末为结点指针为空外,每个结点的指针都指向下一个结点,一环一环形成一条线性链。. M% |3 r5 ?6 a
  链表的创建过程:
$ e% o  i/ E$ c8 |* ~& |& G9 H+ Q
  
) |  U0 X2 x$ J; a8 a5 E4 c. ]+ b- n
  接下来在源码中建立并遍历输出一个单链表。4 G) \% M2 Y, b, y* C" z& ~

3 l* M3 q; M" u1 |" E  k1 _8 v0 Q
6 P& I  W0 t- ~) H
/ g2 [* B% D1 E" r
  1.   #include
    - b; Z% Q4 O% s

  2. ( d9 j( o" q% U9 x* C
  3.   #include
    ! l4 h2 e- X# I

  4. 0 R$ g: X' N& v5 A
  5.   #include
    + C( x5 M: j, B+ R" {
  6. $ q( T( ?0 v! s4 ^3 D9 O9 E
  7.   /*单向链表*/
    2 [+ j* h) t1 P' b
  8. 9 C! k  L8 |1 M$ {: q/ f
  9.   struct Student/*建立学生信息结构体模型*/. i4 x; E$ J; S- v5 @5 S) v

  10. ( j- ]5 \+ e: Y3 I; k" M/ ~0 U6 g4 z
  11.   {  u1 S" Z8 k+ P+ ^

  12. / V4 O9 r0 u  U3 ]$ W8 ?
  13.   char cName[20];/*学生姓名*/1 S/ B- `. Y1 E' I6 _5 i
  14. 0 A+ t+ J, m* C3 V
  15.   int iNumber;/*学生学号*/  O7 {. N# D, [: A% U2 E/ A% a5 C
  16. * T. i2 b  |4 [  R4 `1 o1 F1 w3 {: e
  17.   struct student *next;/*指向本结构体类型的指针类型*/3 I: T1 a: o6 w. q( f6 k* B. c7 y
  18. / D( O/ l# h- t) m5 r
  19.   };5 ~( Y3 W" a, e! b

  20. % L- u. ~) _  {/ ?
  21.   int iCount;/*全局变量表示链表长度*/
    $ E+ a% K+ ^$ j, F$ G4 d" u
  22. 7 W& x7 N* s4 _
  23.   struct Student *Create();/*创建链表函数声明*/
    0 m  L* I) O. a

  24. " K4 M9 l$ v' r. ], T" O3 `& J
  25.   void print(struct Student *);/*遍历输出链表函数声明*/( i  k; C1 i- z4 q

  26. . u; ?+ ]) n/ C/ y2 ?
  27.   int main()
    + }/ ?# P, ?' z7 N
  28. " ^3 B: X8 y! q  h* E
  29.   {
    ! _; ^' {# K" r3 o6 t0 }( U

  30. / }# J8 ?, ]* X- {! i! l
  31.   int insert_n=2;/*定义并初始化要插入的结点号*/
    ! y$ ^; {1 p: x# A" `, i

  32. 2 ?# `( h+ c( S
  33.   int delete_n=2;/*定义并初始化要删除的结点号*/
      q4 P7 O7 ?+ ~5 U2 f

  34. / }. k, J# |" n6 v( \
  35.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/4 l0 I1 w, E$ x
  36. . d0 F4 ]% y# f2 Y/ `! d$ j8 K
  37.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    4 ~! f. G) C6 L+ f

  38. ' w- X1 N. Q& ~! e
  39.   print(pHead);/*将指针pHead传入输出函数遍历输出*/
    - s3 s( L8 M" Z. A& z
  40. ! i8 h. H# T4 T" F( X. b
  41.   return 0;0 ^/ y7 l$ N9 P6 x$ {- J

  42. - R$ Q, s& S: y, C2 a
  43.   }2 f& {* k' g/ r
  44. . ^' W+ P* h: M: _
  45.   struct Student *Create()1 L: q" R' G( R
  46. & `* H* E3 U+ L% Y
  47.   {
    4 U+ d! c; d& m! Q6 G  B) B* V$ l
  48. ) p5 ]: _! C0 J. h! J
  49.   struct Student *pHead=NULL;/*初始化链表,头指针为空*/
    9 g# a/ l  f% A" k5 z9 g
  50. + F3 I7 V! {+ D, ]& \0 z, n1 ]- E
  51.   struct Student *pEnd,*pNew;9 _  K; n' a% ?. |' ]2 K* F

  52. 8 j& N% I0 T9 x. a1 S) S# n3 ]+ v
  53.   iCount=0;/*初始化链表长度*/' g+ F, I8 B$ u) m
  54. & ?# d* z+ W/ ^( C; I7 S5 f
  55.   pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*// h5 \& I5 q; {% ?7 N' e

  56. % x) J6 M: [+ ~
  57.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
    ! J# ~5 e; j. i: X* M4 D/ g
  58. % D, V+ I8 E( n; z
  59.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/
    2 X( h: e  y7 e1 U8 l& }  |

  60. & i: E6 O" N# \  Z- W4 v) L& R
  61.   while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/  i* I1 Z; l$ H4 s0 ~
  62. 2 W; Y( V2 |* m+ K3 Q7 n$ x5 m( G+ v
  63.   {
    : W" T: `5 r2 c9 r) u

  64. 0 r* g6 Q3 U8 G9 v+ K/ ^% z  w0 m
  65.   iCount++;/*链表长度+1,即学生信息个数+1*/9 \; z8 s+ [- Q, t% Y8 e

  66. / |  I, k. Z2 O
  67.   if(iCount==1)/*如果链表长度刚刚加为1,执行*/2 g/ [" Y" a) d7 c7 ]/ E5 g

  68. - u: o, r4 v% D& Z1 P1 [
  69.   {5 W- F% v7 X' Z- L/ j9 s

  70. 4 W6 @- H4 x& E# g) A1 D* i
  71.   pNew->next=pHead;/*使指针指向为空*/
    ) g% G' J. ~8 E* u
  72. $ F. T, ^. q; g  a+ ~0 E- Y. S
  73.   pEnd=pNew;/*跟踪新加入的结点*// P& t7 P4 f- y# K

  74. # x4 V/ U- v' ~* \
  75.   pHead=pNew;/*头结点指向首结点*/
    ' X$ Y% p  D/ @1 s/ k5 ?

  76. % Q6 p" R0 a$ _3 }
  77.   }
    : n+ n9 U; d( y- s* K# e' z, e8 V
  78. 1 X/ f9 C! b; `( x9 F" _
  79.   else/*如果链表已经建立,长度大于等于2时,执行*/
    - d, B, v+ |5 w3 ~) J

  80. 5 P( [; ~3 j0 U- ~4 A! R" B! B, ?
  81.   {
    : _. X2 r% o& @* \: Y' n4 d
  82. , X; W9 l6 b. s; Q+ M, B# `
  83.   pNew->next=NULL;/*新结点的指针为空*/
    " K/ i% k( i; F2 z1 B9 M" W( M+ e
  84. ; q2 @. b/ w( m; r% |
  85.   pEnd->next=pNew;/*原来的结点指向新结点*/
    ( j& R' K' M* ~: L

  86. + |1 P  w9 I: n3 y$ u% M
  87.   pEnd=pNew;/*pEnd指向新结点*/" ]. G1 C, |' G3 e2 w& t' i
  88. + }1 z/ O* o) e0 }+ ^8 C7 }5 S
  89.   }
    8 [0 G3 s/ _. u) y5 ]+ B7 M* ?

  90. ; _* H7 j4 X: b" `
  91.   pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/& v; @# {7 O- K. N* H

  92. 1 t: ~/ X1 t& |( |# G/ Y# J4 Z
  93.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
    ' k* |8 X, k: \% m- J+ d

  94.   k1 \. D+ O  S: x' y3 i
  95.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/8 |" T+ \8 R. i

  96. ) Z) I: ]# K. O! {! S; G
  97.   }
    3 F/ F" z" y+ [0 M; V: g: Z
  98. ; t. t6 E- I" `3 J& n0 h
  99.   free(pNew);/*释放结点空间*/
    8 i" X' z4 l$ n! [

  100. * A/ C- [8 P+ k( f) p, P9 g+ W
  101.   return pHead;/*返回创建出的头指针*/# Y  x+ ^8 F) i( R9 T5 C
  102. : w1 M2 t& U: W1 J/ v
  103.   }( u/ t$ b- i) h3 E

  104. 2 T. [$ M: ]# W
  105.   void print(struct Student *pHead)) r" ^6 m3 x$ V, l5 ?; K$ T- X: c4 j
  106. ; V) h  @- \; @! {
  107.   {" w/ S, j" J3 J# T
  108. $ N) @0 q8 M; ?
  109.   struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/
      m/ q# w- L# e" H) y

  110. ( p% H3 C) `2 J; d3 A. T- Y  J
  111.   int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/
    3 E1 ]9 b' q# M9 ~3 N3 V" l

  112. $ U0 ^* k: X9 {( d- r& n0 t& F
  113.   printf("总共%d个学生(信息):\n",iCount);( i# i1 X" n( U) K4 X. J- u8 ?
  114. + v, H0 I  R7 b* J6 {' {
  115.   pTemp=pHead;/*指针得到首结点的地址*/7 y1 k% v# J% ?8 m! H
  116. " K+ _, [: S2 H1 o$ ?" R
  117.   while(pTemp!=NULL)/*当临时指针不指向NULL时*/6 I( S3 _& N0 x( s! }3 x$ F
  118. 4 \) {/ |; ]4 e: i
  119.   {/ n; g: Q. ~6 r1 k9 M: G1 \
  120. 7 \9 \: P  X) P7 @% _
  121.   printf("第%d个学生信息:\n",iIndex);8 ~/ _( O- @8 T
  122. 4 H6 ?/ T+ g0 ^6 }* z
  123.   printf("姓名:%s",pTemp->cName); /*输出姓名*/! y& x2 j3 Z, D! ^6 e

  124. / h/ ?, a) _: Z0 {# J9 k: n9 s; y
  125.   printf("学号:%d",pTemp->iNumber);/*输出学号*/
    ; D$ ~& w4 ?% }) k. j
  126. : m) F7 u: d/ ?/ z( K) D
  127.   pTemp=pTemp->next;/*移动临时指针到下一个结点*/
      A& U# x5 B! Q

  128. " C5 C9 @9 B7 S( F
  129.   iIndex++;/*进行自加运算*/
    ' S6 n2 u" i( c/ l2 u4 f7 ~# k7 i& _

  130. : _8 K2 h# [- Z7 U9 X
  131.   }
    ! s, F( G+ _, G" T9 q. ?( A
  132. 5 l% I# d! N2 T! P4 G0 T
  133.   }
复制代码

* C" Y) x5 ^- T- V% |) L' @1 F& e; m7 W/ r
& d4 u5 g( J1 Z, U8 f: Q
, m5 C+ E- B$ G1 N1 z! E
  三、单链表的插入与删除. g: w1 U) `. P3 o& r& c- R5 v
  在本实例中,插入时根据传递来的学号,插入到其后。
- x" U* k$ K+ I* i  b. d  删除时根据其所在链表的位置,删除并释放该空间。$ j, i, G6 S( ^6 X
  主函数增加如下:
5 C& \/ B! Q+ Y" i% s
! \4 T% m, J+ }3 C! F! w: K
) Q8 \8 u7 Y4 Y7 Q1 ^5 B8 N7 W1 W: F7 x4 ^2 X- U$ S
  1.   int main()
    # E6 q, G" Q( o0 M
  2. & |* R! C, Z: k# F# `
  3.   {
    * K* g6 d$ @& c/ R. c

  4. 0 \- A8 p, v8 G; V* Y
  5.   int insert_n=2;/*定义并初始化要插入的结点号*/7 n. M  Z# Z4 v" K; U

  6. % r6 F: F4 i3 D+ J# q, x/ C
  7.   int delete_n=2;/*定义并初始化要删除的结点号*/
    7 N% U$ X- w; R% q
  8. 1 T2 I/ j1 S* x. w. _
  9.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/4 ?$ J* ]- X: w- v0 ^- `
  10. / {4 N( o, f5 l3 j, \6 x  b* P
  11.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    - I+ M. v' U# S  G- ]* w
  12. " d  R. e8 E) ^+ L
  13.   pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/' Q4 U( N' K6 F0 T

  14. , p* \7 V- H% R; \  ~3 u# X
  15.   print(pHead);/*将指针pHead传入输出函数遍历输出*/" N1 i4 U. i" M

  16. 9 a4 d9 L3 `0 {1 i
  17.   Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/
    1 C; Q: K: @6 U% `- L
  18. 3 Z( u8 h& }2 T4 {" L# D
  19.   print(pHead);/*将指针pHead传入输出函数遍历输出*/4 K% t1 P, l9 ]3 K4 y/ q' ]. f) D! P, A" f
  20. & L6 Q7 F/ k  c
  21.   return 0;
    $ l6 E$ ?4 Z/ J* L0 J
  22. " a3 }! _7 K/ V# b" A, u
  23.   }
复制代码
* Q. e% N! A" Q: e$ C

. J+ J7 N- h! n2 c! a4 S/ n+ e# ^6 Y& O8 u" d/ d

/ h# }* F% W& G; x# W  插入函数:+ o' y' b8 I/ p8 x
" f% c7 W: e8 v* X* h6 i
$ V/ t+ U+ I+ T

" M4 N$ S  X, ]; y; [1 M
  1.   struct Student *Insert(struct Student *pHead,int number)
    3 T1 e0 {7 A5 r4 ?! ~' p

  2. $ O3 e, L2 ~# q0 L# D( W
  3.   {
    $ S8 C9 h% Y/ U+ ~5 F+ ]9 ~

  4. 0 J9 h5 }! c# i. t
  5.   struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/
    " i& j& X) Q5 D+ M+ d
  6. * r5 d  Z0 B3 y6 m$ f6 C+ P
  7.   while(p&&p->iNumber!=number)
    * s4 t7 Y! ~+ b# Z& x
  8.   k1 ?% ]8 c% V* f# S2 a
  9.   p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/- k7 Z% F* B$ ^' T: U, W, o" k

  10. ! k% B% x( F- |8 V+ K0 z9 r/ T' t# I
  11.   printf("姓名和学号:\n");
    ; \, l0 A3 H  l! @) D3 Q; L

  12. 4 r3 n8 _1 M0 u. p
  13.   /*分配内存空间,返回该内存空间的地址*/2 D6 V7 A* _( v0 L* V, ]3 a

  14. ) ?% D2 E( K' ?0 W( J1 [7 g
  15.   pNew=(struct Student *)malloc(sizeof(struct Student));
    1 K7 Q2 \) f8 K. E
  16. % r. o' v: p" k
  17.   scanf("%s",pNew->cName);
    9 Q4 A/ c# q3 C* I8 Z( C6 n
  18. & z" {5 L" p! ]  l; H3 W0 d! V8 [
  19.   scanf("%d",&pNew->iNumber);
    1 o, Z' z9 w/ o  p

  20. ( h  ^' q& X5 f7 X
  21.   pNew->next=p->next;/*新结点指针指向原来的结点*/
    " y- Z4 b2 S8 a0 I

  22. 1 T  \/ t* U. X2 [
  23.   p->next=pNew;/*头指针指向新结点*/
    3 q) |  I& t- Q7 F- @5 J

  24. 0 Y6 r% I0 H# U: E* J1 X
  25.   iCount++;/*增加链表结点数量*/
    ! t5 O  W7 G, T
  26. 8 H, F+ W# D! V
  27.   return pHead;/*返回头指针*/4 Z# j" n3 Q: S5 l- r* ~2 f9 M8 B
  28. 7 I: r" {& ?8 y& K/ \
  29.   }
复制代码
2 _! H! v7 V# X2 Y0 x
: N. D9 c% P7 N
$ M# l1 P4 ~7 f; v

0 _* A, G3 l% I) V  J$ V' E8 l  ]  删除函数:
/ l( d5 g( t% Y8 T1 ?5 e7 A
" ^, G7 x! L' Z  i
8 A3 c+ E0 y  C, y3 k- K$ v% ]+ ?1 V) h, y: e: i+ s
3 d/ p2 I' |  U  j, b
  1.  void Delete(struct Student *pHead,int number)
    % ?& j" Y7 n4 m# D# m. y2 e
  2. # V1 Z+ y# P& n/ M' i
  3.   {* A& P" q# L; Z$ v2 F4 g, P3 _4 r

  4. ( k5 g* B; ]% a" C- ]8 {
  5.   int i;4 R( }2 G4 d% E% g% Y/ U

  6. * f6 y( T4 e# P& |9 C
  7.   struct Student *pTemp;/*临时指针*/& f+ N+ x- Z1 p4 f4 y4 y: K

  8. $ f( Y: @- u$ }' K& B
  9.   struct Student *pPre;/*表示要删除结点前的结点*/+ t: x( g% `+ `+ {  s

  10. # h; S* t4 i' t8 m3 d, x
  11.   pTemp=pHead;/*得到链表的头结点*/: Z8 p) c$ N* Q1 P: Y3 o/ O' H
  12.   {' W( ]2 l4 r' d; n0 }
  13.   pPre=pTemp;
    1 T# `/ ^6 D$ d% e- N- {+ S9 [

  14. ; V2 A  A) h% U
  15.   for(i=0;i
    ) o7 [7 G% v& x4 x2 L7 `
  16.   J9 c1 M; j7 Z
  17.   {/*通过for循环使得Temp指向要删除的结点*/
    0 [0 `$ W- W' g& D
  18. 6 s7 L9 G4 Q. Y0 T- j5 n: O
  19.   pPre=pTemp;
    : U0 N- T4 X5 I
  20. 9 y+ p' v2 N5 I8 t; Q
  21.   pTemp=pTemp->next;
    # ?' @$ ~0 c  m. T

  22. * `: T6 T) T& k0 }: d
  23.   }4 J* {$ }) J" K, C; j' ^

  24. 0 S" z1 I7 d" W+ X7 t# w  {- ?
  25.   pPre->next=pTemp->next;/*连接删除结点两边的结点*/
    : M$ N0 L' x1 Z+ q' l  X" b
  26. * _8 B5 `/ a, v# p
  27.   free(pTemp);/*释放要删除结点的内存空间*/
    # a. y6 _, x% H& k; D
  28. 8 K4 E6 Q/ p9 d0 |3 `2 y
  29.   iCount--;/*减少链表中的结点个数*/
    . L' [, }; P" X5 K4 \, o/ G( h

  30. ( K! f0 d9 ~5 [% N- O3 ~/ h& {
  31.   }
复制代码

$ B/ I# Y5 T! A+ B1 d
6 s4 W. i4 Z$ C5 N, @4 c
3 [9 D' S4 E0 i$ k  D5 @  四、双向链表的概念
4 d0 k6 ~+ i- K. M  双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。
9 d5 P3 ?7 Q2 f1 F  在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。" p' E, D5 `6 D! b2 r" Q% a
  双向链表结构示意图:% v) u+ X2 U2 _7 h( P

# ^7 Q) B: n. C. |$ Z/ U, f9 [" K; O+ w# ~% ^
  
" ]4 V8 q5 U& P1 ~2 X: d
  五、双向链表的建立与遍历4 Y6 ]  `0 d) B3 Z% i8 t5 C
  双向链表的源码实战和单链表类似,只是多了第二个指针域的控制,这里直接贴上没有注释的源代码。  F+ Z# C" f1 z4 I
  O9 s: p% a4 u' g1 L/ m
7 Q. m: N+ X( c/ d

" K6 e1 e# `% s/ ^* X
  1.   #include #include
    # N" [. ^; n. o

  2. / \5 j( m0 t" x3 d- K; w( E; l
  3.   #include
    5 O, s( L3 t  E6 g8 V2 G
  4. 8 {1 n/ B" h5 D( Y4 p4 \" n1 K) j6 B
  5.   #define N 10
    # Y$ Q3 B) O+ R% B

  6. 3 c  z+ x3 e$ N& X
  7.   typedef struct Node
    8 ~  ~; u/ C: Y7 i9 i$ W

  8. ' `9 q9 m! o4 s' G3 V0 E+ U, g
  9.   {
    . s& H5 Y: ]' C! ]( Y! I
  10. % L* {5 O- O* v  D3 r- o$ i
  11.   char name[20];
    ) q5 {8 {! v$ k; y
  12. 1 Y  a" f' }& x/ A0 H$ ^& k
  13.   struct Node *llink,*rlink;
    : l$ _' g$ O: V9 _% q
  14. 8 Y/ \5 `0 Q5 H
  15.   }STUD;
    7 H8 |2 c& H% h& p' F' \8 `1 W, g
  16. 6 \8 g, N- B) a' e& F8 ?5 w
  17.   STUD *creat(int);void print(STUD *);
    ' L3 l& G, {. c) k1 N* |

  18.   E# _3 ?; f, l. a+ B9 P. x
  19.   int main()
    - t% B+ h" D8 H5 Y

  20. * y8 j) ^* J1 n* V5 [0 L/ ~" h
  21.   {5 ?# Z# E0 l  j: I
  22. 4 C; B/ {4 h" l2 f, F" }
  23.   int number;4 e! z5 v$ Y& M6 ?- j8 ^

  24. 0 J6 [* J0 e" d  h2 p/ Z
  25.   char studname[20];
    % D# R4 W4 J8 V8 v. ~* Q! p
  26. ! W8 r) Y! W4 a
  27.   STUD *head,*searchpoint;2 f  ~& o. ?, ~

  28. + {  u1 `9 |3 \% ~; j
  29.   number=N;2 n9 N% K" z0 y5 G7 Z: F
  30. ' B0 t' k  g/ L2 O3 Y" @  v
  31.   head=creat(number);
    ( R5 G2 k$ q0 X5 d8 I/ F  w/ U
  32. ; U$ o+ e4 a) [$ B7 y! R2 D
  33.   print(head);$ f4 ]$ A: q+ O9 C. e

  34. - T8 I4 H1 Z3 Z* u' K& W
  35.   printf("请输入你要查找的人的姓名:");
    ( ?+ S$ ?5 A5 {) m* b& ~

  36. ( V* h# s' r% C: H
  37.   scanf("%s",studname);
    * v1 C# V. ?3 O# _8 f5 `- u

  38. 1 n6 k0 q% v, f
  39.   searchpoint=search(head,studname);
    + m# z" N* v* P; X- |" Z$ d
  40. 2 ^$ {2 U1 a& Y
  41.   printf("你所要查找的人的姓名是:%s",*&searchpoint->name);
    % n9 S0 L. _3 l

  42. 6 V: r: U1 `: E- d+ n# j7 J0 U9 K
  43.   return 0;
    ; P* j/ q, g% c* t

  44. ! \$ E5 K' @) t9 t8 q6 Q8 r4 T
  45.   }2 U7 c0 M$ ]2 t8 t+ s1 E
  46. : Q; w/ e8 [6 @+ |( u4 o3 J
  47.   STUD *creat(int n)
    . l. j' N! ^3 |. G* h

  48. 9 X, K# q4 ^" D) n8 i
  49.   {
    . r( E2 r% c7 K' o* g

  50.   X" E1 t4 ?. y) U3 r6 X% A
  51.   STUD *p,*h,*s;+ `; ]5 u5 Q3 m: s

  52. % w" c! U/ ]  q; b& v9 @
  53.   int i;8 p6 D% l7 n" v7 y+ H7 J
  54. 6 }, Q5 d" v/ s. g% E
  55.   if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
    8 c5 _/ d; ]- Y7 M9 q, k6 ~- K/ g: W/ [
  56. % I. {4 {0 |6 `1 p- F/ @* I
  57.   {9 w! a; H) b* m; Y& ~

  58. % U( t  L1 k6 w6 a
  59.   printf("不能分配内存空间");
    : T" ?+ Z6 r1 i  W8 Q! r

  60. : q0 c0 @' S: l  C
  61.   exit(0);
    & |! \* A9 _9 u0 V- ]
  62. # o! k8 `2 {9 m1 D* j7 ^
  63.   }
    5 Z' t: l0 ^: C& ~

  64. 2 x9 i1 c  m. A, L6 C+ t
  65.   h->name[0]='\0';3 Z9 j1 D' ?9 a- X' a+ }3 W
  66. 7 F/ d9 ]' [  U4 P0 [$ [0 F
  67.   h->llink=NULL;
    : K& i( P- P' e! Z. d$ _" `/ r

  68. 1 V: L: S1 S4 t- w: d/ u0 T1 o
  69.   h->rlink=NULL;
    ( l8 \0 v! U8 G& L& w1 r5 d

  70. ' i( I: C3 O( u1 e  r4 x. {
  71.   p=h;6 d% P7 E' A( Y0 d5 [) c
  72. - T! h8 X& Q) {
  73.   for(i=0;i
    7 J) g7 e2 D" G

  74. 2 v( m3 p2 `+ n' S3 ^0 l4 d
  75.   {" k/ a' T# I1 \6 D: ]' y% H5 L* S

  76. + u5 h, K1 p$ t7 Y, [1 n" O" [# P, _
  77.   if((s=(STUD *)malloc(sizeof(STUD)))==NULL)% q4 r9 ~" z( V% l# c! }0 y; p9 l

  78. ; F% G4 @) v2 a
  79.   {1 B1 ^) w. t4 w. ~# K1 n
  80. ; I( {0 J  N" Z
  81.   printf("不能分配内存空间");
    + L3 F" o* J, j, W

  82. % @6 n7 _! W4 l6 x: S! ?. [
  83.   exit(0);
    7 y! s, B# h! X9 V
  84. / r. S0 Q. t, [6 S. l
  85.   }
    4 D3 j/ [6 y" z( f7 Y! A0 V0 D

  86. 5 e" e# X) ?! }, ?5 x- u
  87.   p->rlink=s;
    / k) X' L: K& c# T( y+ s

  88. 7 W; p, L& Z) Q  m$ G' x
  89.   printf("请输入第%d个人的姓名",i+1);
    + u3 p1 G: o0 t+ h9 T7 X9 x

  90. 9 t# M2 k0 n2 _1 ~
  91.   scanf("%s",s->name);" w. S0 z% n' f: o' n

  92. 3 p" U8 G! Y$ }8 I: x9 l5 a0 a
  93.   s->llink=p;3 M4 r7 W- P+ E' g$ o: v5 Q
  94. ; k$ Z: D  I0 d3 M
  95.   s->rlink=NULL;; v, C3 h0 Q5 x7 ~# T

  96. 9 K" U+ x2 E8 h2 t' `" Q: `
  97.   p=s;
    0 W' M' j; c0 ?/ J$ \
  98. * a! Q* j2 E! p0 e1 d5 R# G! Z
  99.   }' a/ v9 G1 [* G, K, v

  100. ! h& G. T& F9 Y# F% C( ]2 d$ V
  101.   h->llink=s;+ |8 w3 A9 f7 i$ G% c: f

  102. ) Y$ `. U" \+ _. o: X1 S# q- ]2 Q3 t- n
  103.   p->rlink=h;3 f& @7 x& v8 U2 D9 ^) x
  104. - d3 i' G6 e3 f! |" d& `
  105.   return(h);* ?# \/ Y! H( @5 f# b* Q5 e" C

  106. - @& \1 b( p* Z! o6 S
  107.   }void print(STUD *h)
    + ~$ z5 W5 H, e- p7 m' h
  108. 4 t0 Z; G) x0 U2 V+ ~" h! p6 t
  109.   {& r: c. O# I! v2 U' ^- c- y

  110. ) w! e7 F3 A  ^- u1 F
  111.   int n;  g: j/ ?9 ^8 V0 T; i8 S5 V3 t1 n( Q

  112. ' L7 g5 ~6 F* R' A
  113.   STUD *p;$ H1 W- M* B8 f# Y( y
  114. ( Z9 D, s  Q! J- ~- C2 j7 M- f, |
  115.   p=h->rlink;0 X) E( R! `+ \- b# y

  116. + b0 U5 H  K- J5 A: M
  117.   printf("数据信息为:\n");
    % M' [% W9 z" K- M7 a: x: }+ w' d

  118. # T% S- t+ |$ T* e- V, H  w2 u% a
  119.   while(p!=h)4 {7 b  R2 S. Y
  120. 1 W# U0 s% S7 u' g- ]7 \
  121.   {$ L- k8 M: z' o5 E
  122. & h3 F' }8 ?% X1 i1 R' j, ?
  123.   printf("%s ",&*(p->name));& `- h+ R" `$ t& a. }  Z

  124. ) U+ V! E& i& t6 K
  125.   p=p->rlink;( r( p, F# V2 c: y( D- m: _: }  Q, X

  126. , g% s) z0 ~% u7 y
  127.   }
    5 L8 M! d* l- G: Y9 ~  ?: v
  128. 6 D/ a! `" s. e% n4 j
  129.   printf("\n");
    ' `  b* L4 h4 t+ T
  130. 2 F# N3 D: W' Y0 f( a6 l: U/ X
  131.   }
复制代码
5 V# b6 T/ A; e2 i0 n
: U. {- _( J3 q0 }& s' x2 J
" G1 {& c" W, P/ Z" X1 g- N. @
$ P2 k$ c* B- F7 f6 \- [5 L
  六、双向链表的元素查找/ R0 M7 E4 `* c) }. b8 N5 i
  查找函数 STUD *search(STUD *,char *);
1 D5 v. S7 O9 k0 z  c; |. T
& a/ ~4 j7 E8 f( P. t  R. P# ?2 j1 r2 T: |) K/ O! Y

2 g+ V/ O% U2 m( b0 g0 G! Z1 [6 m
  1.   STUD *search(STUD *h,char *x)
    " G0 c5 j6 `3 k2 g" X8 ^

  2. 0 B5 k) N/ \7 s% i# P5 I
  3.   {' b' D; T* F4 y% k4 d

  4. " q  U- g( O) n- h3 w' z+ o) U
  5.   STUD *p;; _$ Q4 _, B% q- w
  6. $ ^: D1 N# X1 d. ?/ f+ U4 p& d
  7.   char *y;: O1 O) v. X& ^9 D% R
  8. / A0 W" W% b$ d9 Y# g* v, F
  9.   p=h->rlink;
    8 m+ M% G! c. R% a1 F. H: t5 @

  10. ' S% X% ]9 Q3 h6 i6 ?
  11.   while(p!=h)
    - s, c( y  v& A
  12. ! k2 S3 m7 e) G( B1 w
  13.   {' _1 a$ v' |& ]4 t
  14. * c: R% q% u& {( w
  15.   y=p->name;
    % R. H; D' M& t

  16. 8 W  u6 @9 b/ B" O3 x" ?9 ^0 Q
  17.   if(strcmp(y,x)==0)
    & U6 D9 M: j1 u

  18. 9 z. X0 r7 L" Z# T
  19.   return(p);
    : x$ A0 n5 T: W! ?' Z( u% m

  20. " r* d0 {! F) ~: a$ I
  21.   else7 b' s+ v1 ^" a8 O' f
  22. 6 U% i: `3 V7 h' q
  23.   p=p->rlink;& f; o) p1 `" u7 W! f5 E( h

  24. , p$ i$ z* e* s3 a* q) l/ A
  25.   }7 I: c6 G1 x4 x6 u0 S% H/ H

  26. " d- k: i# S* n6 }
  27.   printf("没有查到该数据!");
    9 a0 X' m1 d/ P8 S) \

  28. ( w7 \& l  s% e3 ?
  29.   }
复制代码
& \, p: J1 Z: ?( [' C
; W3 Y5 M% u9 G1 `) Y& \

% V, u3 K' K9 I/ u7 N  @
% z) p3 @! V9 k8 B  七、循环链表的概念: K: h8 O- ^3 B: d/ C
  类似于单链表,循环链表也是一种链式的存储结构,由单链表演化而来。# f2 @/ I$ O0 S
  单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。- S3 \1 W9 [* M. ~
  这样头尾相连,形成了一个环形的数据链。
$ P( m6 o5 F4 E6 ~+ G+ |' a  循环链表的建立不需要专门的头结点。
( [/ K: J8 w' r0 `9 i% {( l  i  判断循环链表是否为尾结点时,只需判断该节点的指针域是否指向链表头节点。& z7 p" b/ I. V% A" }  M, g
  八、合并两个链表的实例
4 P% M* c: n, \( {6 P# A4 C& Z  建立两个带头节点的学生链表,每个节点包含学号、姓名和成绩,链表都按学号升序排列,将它们合并为一个链表仍按学号升序排列。1 z# m' s/ J* D: s! i# O
  算法分析:5 w( |4 I  L- Z4 E$ T$ n4 P. ]+ z3 |$ s
  合并链表用merge()函数实现。函数中定义3个工作指针a、b、c,其中a、b分别指向La链表、Lb链表的当前结点,C指向合并后的链表尾结点。合并后链表的头结点共用La链表的头结点。
/ M5 z) c3 x# J  c6 u* j  ①合并前,先让a和b分别指向两个链表的第一个结点,c指向La链表的头结点。
0 q5 y7 F% Z- X: X: B/ S  ②合并时应该分3种情况讨论,即La和Lb都没有处理完;La没处理完,但Lb处理完毕;Lb没处理完,但La处理完毕。
4 ^) J; k4 R6 h  ③合并过程中应始终将La和Lb链表中较小的一个链接在Lc中,方能保持有序。
  H% n7 A8 |3 g5 O  b; h: y% ]2 u! G" m" Y" F) }
! U. W: v3 A* T' X  \5 ~; u% u! @

  H; A: c" {1 M/ F7 d  r% R2 J$ Z& v/ k% ~+ J
  1.  void merge(struct stud *La,struct stud *Lb)% ?- Z3 f- }! D$ r2 V, X! Q

  2. ) {5 w3 }9 k" o
  3.   {
    ( e3 t4 p5 A1 n9 k% y

  4. 6 V( x+ [9 P( T1 n0 Q% L7 o. s4 U
  5.   struct stud *a,*b,*c;
    # S5 j4 k' c$ t4 r7 J

  6. , \) C3 A6 W! f% D5 u
  7.   c=La;
    2 a& M. T1 P: g9 x7 n* x0 ~: z6 s
  8. " k7 Z1 R0 t  A" `" l" d+ h& r
  9.   a=La->next;/* 合并前 */
    ( R# ?" _0 f0 M2 Q( [
  10. . h  ?- V! N, }
  11.   b=Lb->next;; W2 E9 t  t( V! C
  12. 2 u! N& o; l) X+ `4 w
  13.   while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
    6 D% T7 f1 w3 L

  14. ) m7 b3 Z3 H" i5 M. }9 o5 K; l6 U
  15.   {. L& v+ W% z% G, A* Z
  16. - W+ l0 S$ ?$ Q+ |- P: [
  17.   if(a->num <= b->num); W7 `8 Q! `! i, N6 u9 l$ J' \
  18. 3 _, K8 O/ u6 M8 N0 u- e# Y8 L
  19.   {7 U! t* a' P; p) p* M& m* S- i9 E

  20. 9 y! O% ^* F0 V; X) H0 e; e+ V
  21.   c->next=a;# P7 z8 w$ A4 v: B
  22. 7 }- G0 `( I0 q$ Y" C- ?
  23.   c=a;! M# {" V, p, I: M" p  j& @
  24. 0 o. N# z/ K5 f4 r0 b
  25.   a=a->next;6 `0 \4 P: `- D

  26. ! u) [1 D5 i& O5 ?  y5 v
  27.   }2 [% J7 L" \  h
  28. $ ]$ z6 B+ x& H& ]" Y- o3 }
  29.   else  z9 X) {* U; {8 M
  30. . t6 j; K9 U7 \" ]1 R
  31.   {
    9 f4 }8 y1 z' }: _

  32.   }0 n5 h8 u' d( e
  33.   c->next=b;6 b2 V: p3 D% X' i) E' h

  34.   o! u6 O9 }  v" q" L; C( o6 p
  35.   c=b;8 }+ c+ N1 A2 W2 m
  36. $ A7 ]- _( m+ C5 k! L& W0 K
  37.   b=b->next;
    / ^7 k/ _2 O5 k

  38.   S% a- R! g& L, F* \
  39.   }
    ! q7 g& w, F5 ~+ y: r
  40. % S5 J0 v+ r9 h( M* \' m' P
  41.   }
    " z6 D' ?% R% b$ M# Z

  42. 4 m  ^+ ]' m0 d/ k2 x2 }1 S
  43.   if(a!=NULL)8 Q, D* C7 j9 K, l* k
  44. 4 `  E1 O  K/ B, {4 q4 P- g3 k
  45.   c->next=a;/* 若La没有处理完 */1 ]. k2 T' `2 J) q* M

  46. 0 P* {4 w9 r- J" W4 N& W
  47.   else
    6 v9 g# j0 w0 j( S6 d

  48. 2 T5 V2 q5 Z; U. q0 l7 M8 T; x+ z6 a
  49.   c->next=b;/* 若Lb没有处理完 */
      p# K: Q- D" S+ C
  50. 4 b. m9 c( s/ G  ?3 M4 B: A
  51.   free(Lb); /* 释放Lb的头结点 */
    ( y* A6 b+ e+ M* A% e4 b

  52. ; c/ C2 [4 \( i% w2 G
  53.   }
复制代码
1 {7 f3 \- N4 z. f8 j  m
/ V: z3 t) S; q- ~2 o
0 i2 k0 d+ z; p; w4 z
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-5-24 09:53 , Processed in 0.093750 second(s), 27 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表