找回密码
 注册
关于网站域名变更的通知
查看: 744|回复: 0
打印 上一主题 下一主题

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

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
  最近临近期末的C语言课程设计比平时练习作业一下难了不止一个档次,第一次接触到了C语言的框架开发,了解了View(界面层)、Service(业务逻辑层)、Persistence(持久化层)的分离和耦合,一种面向过程的MVC的感觉。
- s9 R) |& k+ j  而这一切的基础就在于对链表的创建、删除、输出、写入文件、从文件读出......5 k. X" @) h1 I0 _8 X
  本篇文章在于巩固链表的基础知识(整理自《C语言程序设计教程--人民邮电出版社》第十章——指针与链表),只对链表的概念及增删改查作出探讨,欢迎指教。+ x8 d, n$ y' K
  一、链表结构和静态/动态链表5 O# L2 ?; g1 F, ~/ c9 ]8 E- _
  二、单链表的建立与遍历: V( M: G' j7 d! P. ]$ w) n8 S
  三、单链表的插入与删除* k2 E: J; B& Z! f6 X3 G
  四、双向链表的概念
% X+ I! A- t$ Y/ r( V. U; e' l  五、双向链表的建立与遍历2 L0 S0 n! ^2 ?: J% Y* C
  六、双向链表的元素查找3 ?6 F0 Q4 V5 C) @* a' Z
  七、循环链表的概念
- }# x6 W9 U  R$ }. Y# J  八、合并两个链表的实例
2 x- E) `1 l0 ?; W( y  九、链表实战
4 m; P2 k8 j0 u; P5 F+ J$ l  拓展思维、拉到最后去看看 (•̀ᴗ•́)و ̑̑
9 O: T' [# O" _  _2 O" H, s1 B  一、链表结构和静态/动态链表2 x# c, ?+ v1 o; d' m) f# _
  链表是一种常见的数据结构——与数组不同的是:
8 c  x/ q- E6 I# v2 U  1.数组首先需要在定义时声明数组大小,如果像这个数组中加入的元素个数超过了数组的长度时,便不能正确保存所有内容;链表可以根据大小需要进行拓展。
8 _5 u4 o, j' G5 `& |  2.其次数组是同一数据类型的元素集合,在内存中是按一定顺序连续排列存放的;链表常用malloc等函数动态随机分配空间,用指针相连。/ q3 a- ~( I  T4 k, O
  链表结构示意图如下所示:
. F1 A2 A5 ]6 O. K2 j2 S+ d
  
; K! }3 J) Z1 L; A# }" U
  在链表中,每一个元素包含两个部分;数据部分和指针部分。数据部分用来存放元素所包含的数据,指针部分用来指向下一个元素。最后一个元素的指针指向NULL,表示指向的地址为空。整体用结构体来定义,指针部分定义为指向本结构体类型的指针类型。
/ F4 J* M/ A5 E+ x  U9 Z  静态链表需要数组来实现,即把线性表的元素存放在数组中。数组单元存放链表结点,结点的链域指向下一个元素的位置,即下一个元素所在数组单元的下标。这些元素可能在物理上是连续存放的,也有可能是不连续的,它们之间通过逻辑关系来连接——这就要涉及到数组长度定义的问题,实现无法预知定义多大的数组,动态链表随即出现。
$ S1 y4 H: }6 O# w6 D% I$ ?% I  ?  动态链表指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点的数据,并建立起前后相连的关系。; A3 h4 g3 E, K+ y, o4 c+ H) q# x
  二、单链表的建立与遍历
. @8 n" g( r( y! b4 |/ K6 [  单链表中,每个结点只有一个指针,所有结点都是单线联系,除了末为结点指针为空外,每个结点的指针都指向下一个结点,一环一环形成一条线性链。
4 e% Z  \& w7 y+ _/ X" N9 A* I! e  链表的创建过程:
" D: E! Z" E! G' u7 W1 z1 s
  

! h5 c  ]( X1 b  接下来在源码中建立并遍历输出一个单链表。# j" [. _& E$ X
9 V- X/ l8 u- F, f

! x2 d- F0 s6 f; V- X
# m. ]1 K9 d; h/ R6 u# B
  1.   #include
    3 [- K$ u( n3 z' X: O% s, m
  2. ( Z$ L! R. }& y* L* o1 N
  3.   #include; v7 |! @% a7 ?7 g4 U# e1 W

  4. : I4 q3 b; w  o2 p+ z* B# I
  5.   #include
    5 @% U; f4 S5 x
  6. 6 o# m- N9 O" K7 o& a/ V: a
  7.   /*单向链表*/
    $ t5 \6 X9 ?1 W" J+ k+ c$ q$ r

  8. . G  N) y4 {- f2 Y' w  {
  9.   struct Student/*建立学生信息结构体模型*/
    ) Q" ?* J) Q* [+ s. s

  10. ' l2 t* n7 C9 W/ T/ e: n2 Q
  11.   {
    , y* W) k2 q0 L0 y) E# z$ X3 I
  12. & r9 M% K! V' f+ B6 z
  13.   char cName[20];/*学生姓名*/' e: n1 ^* r6 x0 {  i
  14. . _9 @' q7 Y, x. K$ M4 D2 i
  15.   int iNumber;/*学生学号*/
    3 ^; X' G# b' w: @7 {$ u

  16. 9 z9 h4 B' u1 q4 L
  17.   struct student *next;/*指向本结构体类型的指针类型*/8 b! }- d2 O; [5 `2 T3 i
  18. . t" Z( k" h& I% C, T9 r7 Q
  19.   };
    9 j; I1 W" D: N; P

  20. ( J; A1 L3 P" @5 T! B' b) y4 ~  f5 k
  21.   int iCount;/*全局变量表示链表长度*/
    3 u1 Z6 Q% |+ @5 e

  22. ; [2 {, u8 L' X) L' E; x/ s' g
  23.   struct Student *Create();/*创建链表函数声明*/
    * ~9 x4 |0 D- I$ \3 w. N& e

  24. & M9 _$ ]0 J" d, w
  25.   void print(struct Student *);/*遍历输出链表函数声明*/1 V3 z3 x8 @( P+ f8 I; |

  26. " d/ W5 C0 e( e; P& D- I9 l$ C1 Y1 s! `" y
  27.   int main()" y$ g; Q# u% @% C& g

  28. * r* B% I8 V4 V$ w1 `# {
  29.   {
    ) e( o: ]1 U. F8 A9 Y1 H$ f% u
  30. . {; ?" W9 E/ }( m# q8 \
  31.   int insert_n=2;/*定义并初始化要插入的结点号*/2 b6 a# }6 S0 v2 f: W, A, q

  32. - p9 _- s! R/ S4 y, l0 J
  33.   int delete_n=2;/*定义并初始化要删除的结点号*/
    / [- h6 g$ l  m5 p: [3 @

  34. 6 s% S5 j1 ?$ X+ X' j" i: t/ u
  35.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    / j# G: k# \# v  C' C" ]
  36. / c7 O7 x6 z0 n
  37.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/+ d8 ?& ~( d0 Q! h+ f

  38. # H/ O' w3 n  t7 h2 x  E
  39.   print(pHead);/*将指针pHead传入输出函数遍历输出*/" P; }5 o# U; v4 \
  40. # A( {1 ]' o: r' L9 g
  41.   return 0;2 A7 K) m0 ]! {: Q" E
  42. 2 {& y/ t7 s4 P0 @) {9 i% p& \
  43.   }3 c" ?5 z8 i9 V$ E. ~6 }

  44. ( _1 R' G1 z4 X# q
  45.   struct Student *Create()  o. j7 a' a: H# |7 h" j* S# o
  46. 8 x' ?  u4 j, A+ p
  47.   {
    - s) O; Z" i/ E: M: I3 F1 W) u

  48. / n# n) o% t' }' B0 v. m
  49.   struct Student *pHead=NULL;/*初始化链表,头指针为空*/
    ! z$ j7 {* [) U: p0 o0 R+ t3 C4 E

  50. ; d: h8 N) G1 g3 ]; L
  51.   struct Student *pEnd,*pNew;) U7 c$ ^* }9 ]4 A: B5 ^5 q' D
  52. 8 Z, T1 L; Y4 Z
  53.   iCount=0;/*初始化链表长度*/$ I9 ]# a: E" C4 K
  54. ; \& x) i' g5 M4 W
  55.   pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*/
    7 C( p/ k' z% w/ c

  56. . t! R. _( b* K( d- k$ }& N
  57.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
    ' g$ b  o+ B1 C) Q/ {8 _4 I5 c
  58. 5 e6 B1 c7 M3 j0 P7 S! R) G, j
  59.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/9 c, q3 r7 Y2 B/ C1 O7 I7 Y
  60. % t8 n4 U3 R. Q" W- D1 G
  61.   while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/
    - P! i5 t$ V; t( @% y

  62. & {/ N" N* Z5 Z: h: ^
  63.   {
      x- C. j  B4 D7 U
  64. 4 p$ z/ @7 `- t! b
  65.   iCount++;/*链表长度+1,即学生信息个数+1*/5 {; D- L7 Z5 ]. w2 z
  66. $ q8 e# }- o) H* X1 N. D
  67.   if(iCount==1)/*如果链表长度刚刚加为1,执行*/
    ! [' D9 V! }4 U1 ]0 A$ ?. o+ ^

  68. . D8 c+ e: }: y$ b1 I% g: ]
  69.   {
    $ r1 y: T5 r2 T! c. L- u2 @

  70. 1 U7 L2 X& Q/ W% l+ s, B' L
  71.   pNew->next=pHead;/*使指针指向为空*/
    8 D$ Q; `9 U/ G4 T0 K& `/ n  Y3 ?
  72. 4 s& H% f* l; R' i2 `9 k) a
  73.   pEnd=pNew;/*跟踪新加入的结点*/) N/ Y# p4 R7 A) V% t' Z
  74. 7 V- _" S/ A) n1 s! J: l% R: ?0 K/ O
  75.   pHead=pNew;/*头结点指向首结点*/5 {& |! c+ h3 H0 K, H* h1 k
  76. ! T& k; R- ]6 s! @( }' r7 d- L! Y
  77.   }! l) T+ m8 A% [9 G: |/ c' G
  78. + N/ E6 e; i6 j) [* q  j9 S) ~* q+ h. G. c; W
  79.   else/*如果链表已经建立,长度大于等于2时,执行*/
    6 U7 E9 p$ g8 }  d; z4 G
  80. 8 @1 Q+ ~* y6 a" {& r7 U" K
  81.   {) x$ ]" f6 h; z
  82. ' u! }8 x. {! |/ t7 ]% t
  83.   pNew->next=NULL;/*新结点的指针为空*/. y! r9 ^9 A) D7 A- M
  84. 6 \% g# d, ~' M; F
  85.   pEnd->next=pNew;/*原来的结点指向新结点*/
    ; t) @4 u+ c; o# b

  86. 0 @( g1 @, E) x/ {/ e. w" [% p  T2 T
  87.   pEnd=pNew;/*pEnd指向新结点*/! l& E. I3 b- E

  88. ' V  s6 `9 _; E& X! Y9 i, n
  89.   }
    . X* G6 R# G$ F* a! ~9 S, ]
  90. 5 `' X3 C6 y7 ]% i" X" B" B3 H+ w
  91.   pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/3 c8 ?: U0 ~9 T: P# J/ T$ `' x
  92. 7 \0 i+ m. p7 a; L. I
  93.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/% t. D- b+ s4 M5 [& ^/ ~% k
  94. * B' w* a" H2 n' L. T( B# m6 H. P
  95.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/4 [. n1 C: F6 l+ Q1 B: [

  96. ' ~* r3 A# t' I+ \
  97.   }
    0 f- o* @5 c! ?, r
  98. & L4 f3 `$ C$ }4 l1 y
  99.   free(pNew);/*释放结点空间*/) ~# Q) s, x. Y& d' Y8 [" K. I

  100. 9 _) v- H% r9 p0 X
  101.   return pHead;/*返回创建出的头指针*/2 V6 B5 m  R7 M# k( _

  102. 6 `/ L2 M- x$ \+ Q0 i! H
  103.   }
    5 M! ]1 v1 |3 o

  104. 7 C5 U! }, C  M) d
  105.   void print(struct Student *pHead)- A; J$ P' G% q. v' H
  106. - T; W2 d5 X5 u  b6 ^+ z' Y
  107.   {; t/ K! O( s3 |
  108. + S' M& m' o1 f' `! y2 S
  109.   struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/
    % ?# v1 n: k" s! V' E+ {4 Q

  110. 4 E! Y* c/ [& x! f5 C8 F0 V
  111.   int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/
    " m4 o- r0 d  k0 P

  112. / n0 d% t- @* v! z! Q( t
  113.   printf("总共%d个学生(信息):\n",iCount);4 t6 E( z4 U) k7 u8 e( c/ `

  114.   L/ a5 {2 e  [7 o0 ]
  115.   pTemp=pHead;/*指针得到首结点的地址*/4 w8 [& y5 }8 |" B5 X" V! w; y& ^5 t

  116. ! L% t( ?0 f! P7 `1 |( Z8 F/ X1 r4 K- j
  117.   while(pTemp!=NULL)/*当临时指针不指向NULL时*/: `: S- w$ j8 D5 @9 D) ^' p; B* y

  118. & T( r" {' X/ i  ^+ v) K% \
  119.   {0 A: O( l. Q! l) b9 v) o

  120. ' }; @+ K' w* S/ E* o. R% Y
  121.   printf("第%d个学生信息:\n",iIndex);* r6 ^2 K( N# r, s0 J/ ]5 z
  122. 2 }: t% D, ~1 _1 Z
  123.   printf("姓名:%s",pTemp->cName); /*输出姓名*/$ R" v; I5 G7 @+ `  e

  124. 0 l' I3 g+ M5 b; j
  125.   printf("学号:%d",pTemp->iNumber);/*输出学号*/  n1 S5 M3 U# D

  126. + D9 g) @+ S- x. j
  127.   pTemp=pTemp->next;/*移动临时指针到下一个结点*/: Q& O7 {: N* ]
  128. + z- E9 _" T7 I
  129.   iIndex++;/*进行自加运算*/$ }- v  }) T9 \2 ~- D4 e! g" m
  130. & a9 u$ Y% A- U) i
  131.   }
    9 [( S) W8 ~, i4 f8 Z6 A/ e$ y
  132. ! p# Q, e: m( \: W( F8 Z6 f
  133.   }
复制代码
! A& n5 S, V2 ~( p. q

1 C* o$ v0 ]! P9 V& E0 h! l- a5 a" @1 d+ E% J3 I

" L$ _+ d/ H7 d1 V% l  三、单链表的插入与删除
+ ]3 Y1 f' E6 `  q  在本实例中,插入时根据传递来的学号,插入到其后。
; Z- F# e  o9 B: Q! }; S  删除时根据其所在链表的位置,删除并释放该空间。
) q% ~) [; B% E+ i. _& E  b- L  主函数增加如下:
/ r2 ?3 q* j' M3 E. C& C6 V7 E: S
( V; L* k, i3 K% _5 u' b! N8 ~3 ^( ]1 T+ a9 q5 j5 e% K3 n
5 L$ q. C* y) o$ G
  1.   int main()% j) a/ b- s1 k
  2. ( _5 N' Q) d1 f  S* R
  3.   {  I- D* J9 r! u5 K# t+ R8 N2 P0 y1 b

  4. 6 }: w9 z; Q6 U) G. D" g. T
  5.   int insert_n=2;/*定义并初始化要插入的结点号*/7 }1 Z# s9 u, w* G) `

  6. 1 U$ E* K( t  {# l% T
  7.   int delete_n=2;/*定义并初始化要删除的结点号*/
    / z/ X$ x( H7 A, G% ?. b9 E
  8. ; a8 F. I1 e5 h! l
  9.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    9 u- p0 ^4 W% H; ~( J: K

  10. ) t" Z3 U- k# ]* n
  11.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    3 ?. h( b9 @1 `& H/ s

  12. 2 g; i% a. K# u2 H& w- b
  13.   pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/3 k2 z- }! v' m* |
  14. 9 k" F- s! f4 q: D7 w1 p8 ~
  15.   print(pHead);/*将指针pHead传入输出函数遍历输出*/
    9 p3 S: E5 j# t$ V% J

  16. 6 \! M" T) w- D: U+ z) w  U
  17.   Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*/5 \+ z! H9 t# W/ ^9 c3 c) g

  18. # D2 S' V" _  V" {& @! n. Z, G
  19.   print(pHead);/*将指针pHead传入输出函数遍历输出*/
    ' }1 S& `! H+ ]! n, T$ v% c

  20. ) f6 G& s6 p! o& D3 Q
  21.   return 0;
    ) `9 a. f9 I. }3 m
  22. / X( B6 h9 F( p. d; t6 P* _
  23.   }
复制代码
  a  l' M! Q9 u6 k- Q6 T% r+ ?
1 v# K$ r$ Y- Q6 C* `

4 m3 ?" h' d& L$ I
! z$ u' l* |2 N; M" A+ g5 f8 p  @  插入函数:7 n2 l: [+ S( I% @* |" E& ]
. ?5 |. \+ `+ H3 |# e( g  L% b
' ?3 ?) f$ f& |5 j; j9 j4 m
+ `# L$ `. d3 }7 ~
  1.   struct Student *Insert(struct Student *pHead,int number)' J2 `6 X6 i; N6 @) u8 t  W& f" J
  2. 2 X+ ~& T: d& ]0 D+ M/ `
  3.   {8 Y7 {0 d2 {5 C( H
  4. % e+ P& I9 v- h- y; [
  5.   struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/8 B/ b6 P! ]1 M- _
  6. # Z5 |+ X( r+ @$ Y  I4 n
  7.   while(p&&p->iNumber!=number)
    ! {2 \5 C& y8 A$ u6 a6 k9 q- N

  8. , v' X8 |3 E* Z+ [# c
  9.   p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/4 z# s( M7 c3 V1 @# t( u) ?# a1 ~
  10. $ `& O+ ]3 p% s* u) u
  11.   printf("姓名和学号:\n");
    8 E3 R# p1 ?" w1 ~# R4 m% W
  12. 6 ^* h! M% [* W9 W  v1 [5 L
  13.   /*分配内存空间,返回该内存空间的地址*/
    8 D3 M: c: j" x& k' \7 j
  14. 7 a- ]. ]7 ~4 k: G" A* G" n6 i
  15.   pNew=(struct Student *)malloc(sizeof(struct Student));
    3 m. p  f9 Y2 n' `9 n  J
  16. 1 H# U( L# e  ?# e  j% Q' g6 y  F
  17.   scanf("%s",pNew->cName);
    ! g9 p" L* G: y7 ]) q8 x

  18. ! M. k8 u, b8 }( |2 Z$ ]' ^0 a6 L
  19.   scanf("%d",&pNew->iNumber);  o  R0 G% `# h' u9 o3 j
  20. ' c1 `) s- P; T# L3 k3 ^
  21.   pNew->next=p->next;/*新结点指针指向原来的结点*/
    + S% b, E5 B+ k; J$ c- S9 {

  22. 6 W5 M- [% S& B3 M3 W. S8 ]* D4 [
  23.   p->next=pNew;/*头指针指向新结点*/- k5 u$ W3 t% L/ b* V* ?. h

  24. ( ~4 \% `) C- w0 A
  25.   iCount++;/*增加链表结点数量*/
    9 Z6 M( j/ z! d8 }
  26. % ^  z7 H% G& C# G! x% C
  27.   return pHead;/*返回头指针*/" {- F! e8 P# B  g2 w  D6 ?
  28. - Y$ U' H! I( d' n9 x7 g* M
  29.   }
复制代码
5 v# C4 R; n9 ~, d

& d4 `: J9 A" @9 a
4 E" [. ^' H& I2 I9 E+ f, P1 P, [
  删除函数:
. q; @0 C# Z' O  {. ?0 a6 I1 @2 j# l9 ?- M5 u7 n- H) q

. N0 F5 S+ G' i; y! i8 S+ K4 c$ H! w3 N- }+ L+ J9 S/ B/ [+ i
5 h7 G! [$ E* M, A" B* V3 T4 P2 U
  1.  void Delete(struct Student *pHead,int number)' Y' }5 y1 M- h# P0 ]
  2. 2 c% g& @6 x% U  {( E. d# C
  3.   {
    3 a8 z7 s, F6 R* F$ Y% @8 M1 p3 f
  4. & {& E0 C' Q0 u1 W5 V3 ]3 ]2 Q
  5.   int i;0 I$ ^' a, {) Y( p

  6. 1 b; |1 N! Z: l7 T. t! B0 V( y
  7.   struct Student *pTemp;/*临时指针*/
    5 J2 V6 ^; O4 w% b5 F6 w+ E
  8. $ S- r' `; {8 a3 x2 h% J! t, |' H9 v
  9.   struct Student *pPre;/*表示要删除结点前的结点*/
    ( h2 I/ c$ U7 A% U1 p' f0 o

  10. 1 i! n- N2 g2 o: ?+ i- P
  11.   pTemp=pHead;/*得到链表的头结点*/
    ! s" Z1 D7 S2 I; L0 F

  12. ' F' V/ Y' H$ M7 X" P
  13.   pPre=pTemp;/ q, ]6 Y4 }. k2 B
  14. 8 v9 X2 r( m1 y* b7 [  @6 S
  15.   for(i=0;i2 D! o2 z3 [* K: v
  16. 2 @. F6 t- x$ ^4 }6 |( X8 N4 d
  17.   {/*通过for循环使得Temp指向要删除的结点*/: q+ K7 o+ e( Y( d0 r) L
  18. ) [4 l4 r. V' e; c7 I
  19.   pPre=pTemp;1 n7 V; }: N+ [& |  l0 b8 M$ x) [
  20. 9 ?( j9 f+ N1 y
  21.   pTemp=pTemp->next;
    9 @0 e9 x2 \, |4 u8 u3 \9 P8 I* O8 j

  22. / H5 d6 t8 |5 v
  23.   }
    9 b" J& r  g4 D2 j2 b
  24. - ~' ~6 B) u" ?
  25.   pPre->next=pTemp->next;/*连接删除结点两边的结点*/
    + ^0 q$ K2 Q" L, q7 E2 R5 t
  26. ( d( T5 b5 ^6 t2 U5 ~; \& |
  27.   free(pTemp);/*释放要删除结点的内存空间*/, x5 ~2 ]: r) k5 U- _0 T5 Q

  28. & S5 v5 V6 x( C4 b
  29.   iCount--;/*减少链表中的结点个数*/
    + s5 L5 X( q; f1 s; d; r
  30. " ^8 D. U2 n, ~4 i1 U4 ~: Z
  31.   }
复制代码

1 g- C' a+ A; x2 w6 Q0 A
  C0 D  J! e7 d9 W& F' s; p6 S% d8 A
  四、双向链表的概念
3 G% {& N& b5 O! N, Q5 F  双向链表基于单链表。单链表是单向的,有一个头结点,一个尾结点,要访问任何结点,都必须知道头结点,不能逆着进行。而双链表添加了一个指针域,通过两个指针域,分别指向结点的前结点和后结点。这样的话,可以通过双链表的任何结点,访问到它的前结点和后结点。: S/ S- F. @8 ?
  在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点的地址,一般称为右链域;一个存储直接前驱结点地址,一般称之为左链域。
, n. ~2 ]* Y( _- D# ?+ g  双向链表结构示意图:: z* C' D3 E% s; o+ Q( D  M
4 z# G% ]! }! i

. K' E0 E: Z+ M7 N( l6 p  z9 i
  

, K# s% c" O; o1 V  五、双向链表的建立与遍历
- R2 h; j; b; A  双向链表的源码实战和单链表类似,只是多了第二个指针域的控制,这里直接贴上没有注释的源代码。
& z* q+ I, F9 u
/ I! o  F+ D- E& _: ~, q) |5 \! a) ?( k1 K) S! T
2 s! `5 U- f) G1 |5 e& w
  1.   #include #include' W5 k1 g& k" n: O% E

  2. " b: G  Q9 d2 A0 U
  3.   #include5 N; d8 _$ h2 h. m& |  L+ _

  4. ; w$ k6 b4 x) r# R
  5.   #define N 104 y  `4 z( W" P+ f) p8 w

  6. 0 V2 T$ H, N+ \
  7.   typedef struct Node
    / ]2 y: U" s! G- N9 X
  8. . r" i+ D. o1 P& g5 b$ v+ {$ _
  9.   {  n9 T( W7 i9 l4 O7 q" ^& m

  10. ) x3 T* _8 ^8 ?4 k
  11.   char name[20];% e$ n" B2 X! C: R' z; X1 J
  12. 2 d5 T! s2 l7 A8 F' t
  13.   struct Node *llink,*rlink;: e9 W7 \' P/ D6 j& w4 `) X1 V

  14. - y6 d6 m- _  L
  15.   }STUD;; S! A# k5 s2 }
  16. ! H+ ?! _) ^! |' z7 u; I; F) o. s8 c
  17.   STUD *creat(int);void print(STUD *);
    % [/ d' W, @4 K  {- ?( P# \

  18. & ]3 ^0 V  L; F' w  P7 y
  19.   int main()* k( o% X6 k. ]5 q/ y

  20. 0 Q  r2 D! |8 {% x5 y
  21.   {# b- z( z1 `3 d& u& l/ G
  22.   {1 f5 f* l2 U, p4 K
  23.   int number;
    6 Y3 H, ?4 K; X+ Q7 W

  24. 8 S8 \* W9 I# ?9 F3 o
  25.   char studname[20];
    , ?3 J0 B, P, _6 k+ ^

  26. 5 f( V0 M# ]( V+ b( G( F  n
  27.   STUD *head,*searchpoint;
    ! p; o( i/ V* B- ?

  28. 4 P! T, p3 w6 S4 S$ u6 h
  29.   number=N;4 Y) H! j2 @4 U* j0 x0 Y( D5 Z

  30. 3 k+ p3 a' _) b% [/ t! z
  31.   head=creat(number);
    9 R9 g+ _4 o' `9 x4 N

  32. 7 Y, x# F/ n) P1 }$ I: u. h! d- i& t
  33.   print(head);
    * r: P/ O# h8 m( U( L+ g# M
  34. ; |0 v; D) e! C& [3 i2 h0 I4 m* a
  35.   printf("请输入你要查找的人的姓名:");
    7 J# n4 D$ W3 ~3 `
  36. " ~  ^  L- N" e/ E5 ]: w
  37.   scanf("%s",studname);$ [" Y- X  p  k  Q# X: U; z
  38. " l' ?! g: |6 T/ G
  39.   searchpoint=search(head,studname);
    6 p4 O, T/ ^  _5 a

  40. ) A! P0 Q* K$ D  }2 Q  N( c" M6 F
  41.   printf("你所要查找的人的姓名是:%s",*&searchpoint->name);( T* a% |, S! Z8 [% F0 [

  42. 8 X: q7 R! R, W$ v/ i( @* a  H) l
  43.   return 0;
    7 ^$ ?# ?: m, [1 o( o, \: n
  44. : k0 }% Q  L0 k
  45.   }5 s/ O1 _8 @. C) `3 `# u: H

  46. : t  K4 B9 u" Y* g
  47.   STUD *creat(int n)
    # u, V7 Z  v5 e
  48. 2 r, A1 R% x, w+ f& v) K
  49.   {
    & I3 H( f7 a# O3 v8 I6 L) ?7 ~9 v
  50. # M* V) p! u* O( ~: f8 {
  51.   STUD *p,*h,*s;
    . a3 g1 I& K# W& y" K( w' K

  52. 4 G& H5 A- ~0 k- K1 L5 }
  53.   int i;/ b/ `6 o9 t3 e" s

  54. 7 i: U- p3 N, a0 J+ Z
  55.   if((h=(STUD *)malloc(sizeof(STUD)))==NULL)$ S8 e$ `1 ?) ?6 g6 |4 p

  56. " |) o! P1 z* m. z' d4 P
  57.   {
    " T& e" b: F4 P* n) t# d1 J

  58. 5 U/ i+ w8 b: x( ?
  59.   printf("不能分配内存空间");5 V& V& ?: d# Y/ s3 T6 R( S

  60. 9 d7 K5 [; a; k: w
  61.   exit(0);. r6 g: \8 D; X2 f* ^( m3 u, a
  62. & O2 k2 r, D) H  V
  63.   }! r+ x  G( a5 r! J7 B/ m

  64. " y) f: j' Q% K# k6 ~# A
  65.   h->name[0]='\0';& K1 J, k6 A0 e  B) N* U' F
  66. 4 P& O$ \, m- H; S( I
  67.   h->llink=NULL;
    . v8 Y4 g( d0 I* u$ f6 @( Q

  68. % R- h9 ^2 d* C# C# y3 s
  69.   h->rlink=NULL;
    ( z9 L6 E) I$ p

  70. : K5 v1 L* s7 X( T# i* G! m
  71.   p=h;
    . j9 f5 N9 V0 R! M6 `
  72. 3 ]$ Q* ~; Q) a( F7 L7 `
  73.   for(i=0;i# O: D; i* V! c# Z, T3 G
  74. 8 K$ \9 k+ J1 ]
  75.   {
    9 ^3 H5 I  Q( Z9 `
  76. - `6 b; `" J1 H6 {( P2 n* p
  77.   if((s=(STUD *)malloc(sizeof(STUD)))==NULL)& f$ \) }3 |% Z2 j" ?+ b, N

  78. 4 x+ Y( ]- z7 W0 l- v
  79.   {
    0 P+ k, [/ e- P4 q
  80. # ^! z: b& s" R; x3 g
  81.   printf("不能分配内存空间");
    / c; Q0 g! v5 ^. G* \/ S6 k
  82. 2 W5 I3 F1 D  t, W8 H, t
  83.   exit(0);6 f# ?' B( N( ?1 X
  84. # Y4 [& I3 g+ c5 f
  85.   }  U& y! S6 t) M8 z" f! F8 `, {
  86. ( g" f& J4 L! P) u! P5 b0 O" e! Q
  87.   p->rlink=s;1 W: `/ r# w+ C7 }# `, A/ P

  88. 7 o  r3 W! A7 X! n( C
  89.   printf("请输入第%d个人的姓名",i+1);
      {, C) p; n" \! b1 G# y+ f* B

  90. 2 n) h; F" l$ A, L5 E9 x& y& ]
  91.   scanf("%s",s->name);7 \6 d0 O2 [+ k2 p9 R3 L
  92. + `, j9 l2 ?1 U/ m0 v* R
  93.   s->llink=p;. j6 {7 A, A4 u& _

  94. 4 B" J- h8 t+ J% P
  95.   s->rlink=NULL;
    6 W0 i8 p( L) N& s9 t  c3 V
  96. 3 n: a0 T4 _; q  L& v9 m7 |, q3 O
  97.   p=s;
    : c% j0 m; n2 m1 N2 C* i2 I! @
  98. + h  P* V: S# D  k( p9 A
  99.   }9 l( L/ T" g5 m
  100. 5 x% B  c+ X$ H$ x5 I9 `* X
  101.   h->llink=s;
    " Z$ n% {4 Y, |7 b, {& c) v

  102. ! T8 Y5 q1 [+ t* g, x
  103.   p->rlink=h;
    ( B. L  ^  F! q/ `

  104. $ A1 N0 w6 w+ W! l! j7 w% ]3 ]
  105.   return(h);4 G) Q9 t7 {% ~+ V! b

  106. 1 b! g# C+ h* ]7 Q8 z; z6 N! a+ q
  107.   }void print(STUD *h)
    5 J# s8 X2 X: ]: U+ \0 C
  108. % u( L% s% ~, I' S0 b( n. `7 L
  109.   {. i/ c: V- G" ]" _
  110. % p* Y: }7 ]! A5 c0 G2 E' s
  111.   int n;
    5 [* d. r  S( m) ?( D

  112. 2 y' u! b9 |! m6 F
  113.   STUD *p;* ?- N, i3 b' M1 E

  114. $ U" C9 |5 V& @) L- w" y
  115.   p=h->rlink;
    7 N' t3 L6 ]- J9 s' q

  116. % D7 R0 D, D0 m& s
  117.   printf("数据信息为:\n");
    6 o0 }5 Z& |( a
  118. 5 J8 @6 C& }) {
  119.   while(p!=h)
    1 Y+ O9 K0 L) O+ C

  120. + f5 d# d: d* h* H& Y- X
  121.   {0 [& ~% ?" T' P9 p+ M& d3 x, R

  122. 0 u0 M7 i. y  x8 n# Z2 m. N
  123.   printf("%s ",&*(p->name));: [, J8 x, `# q/ P3 _/ V  b
  124. & m' a. ?  l: h9 s; c. z2 h& z
  125.   p=p->rlink;6 k& j2 `1 w# d; n4 x) h, x2 ~/ E
  126. ( p0 N+ x. Z6 [9 k6 {
  127.   }
    2 W5 O9 S2 a0 i) T

  128. 2 A3 ~! u% e0 I2 d
  129.   printf("\n");; N6 J% x) [% D, U" y
  130. 8 Z  k% V! b4 E9 f7 O2 H" R
  131.   }
复制代码

5 ~" L7 }1 W) }5 w8 I8 {7 f) n) W2 m" J9 J  @% I% |" G* ^' n/ @+ j

5 v( I7 }% W2 \+ z( a7 N: O; H
; j) S, _. _$ n& h0 L# J& B  六、双向链表的元素查找
- V+ T% g/ R9 }/ S  查找函数 STUD *search(STUD *,char *);
8 ]. o# s/ }$ W0 o" d+ [/ P' T$ O( n! L# {
. z' g: H1 y1 k8 q( p: a

. v% p, h$ t  S: R7 W. D4 r
  1.   STUD *search(STUD *h,char *x). c% I3 h7 c' \0 A# w  n

  2. 5 J( Z1 o. l5 A9 N- J0 f! ?
  3.   {
      u# U  h: Z5 p7 y8 M4 A1 [, k

  4. # \) S. S6 U- v( A7 }, U7 k, J
  5.   STUD *p;" t4 h$ G1 `0 U; K" X
  6. $ A1 T+ L1 y: o9 W9 h, a  q+ L
  7.   char *y;
    ; v4 [# Z4 h9 }" H+ C

  8. & I. B! x- Z2 A! b* D9 r  t
  9.   p=h->rlink;
    , Y4 r* `% ~, n# D4 r; u

  10. 6 ]( D+ J: Y/ f* x& Z0 I
  11.   while(p!=h)
    ( W2 _: {/ ?6 c# O, t4 \( q0 q

  12. 2 [( W+ t# F7 i/ ^! W
  13.   {
    ( H% P# x" v' ?! B) F3 h9 z

  14. 9 z! E$ [8 W- J* z9 `
  15.   y=p->name;
    6 E/ B. Y9 S. a1 O0 w, }

  16. , [5 Z& w  m1 i0 f  n5 r
  17.   if(strcmp(y,x)==0)
    + L4 ]+ P+ e$ s, O( W1 a7 ?

  18. % ?- v; B+ U, H% Z& V
  19.   return(p);
    ' I  F3 E4 w' Q/ x
  20. ' }% X  C, ?6 V. e
  21.   else( e6 @8 K5 _0 u6 p* Y6 }
  22. 5 i2 `" s5 Y! P  L7 O
  23.   p=p->rlink;
    + q1 c2 S8 I: i% R
  24. ( K  G6 B# k; S. F- O: f( {2 y
  25.   }7 M  t4 X  k. S* Z5 z. ]

  26. $ H* q( Y, I& H4 V
  27.   printf("没有查到该数据!");
    5 F5 `( L! U6 n% f# q- T
  28. ' K, p) F  C# Z6 h/ {. C
  29.   }
复制代码
1 b3 v7 f7 D8 C- H! E3 o. V: ^2 ^
0 i4 V4 Z, n) k7 M: a7 ]
& \* n, p+ Z3 D0 {/ O; ~
# m3 A8 r9 \5 V* ]" j0 d! r- J( ]
  七、循环链表的概念
6 @" f$ `% B% C  O/ H3 s( Q! S  类似于单链表,循环链表也是一种链式的存储结构,由单链表演化而来。* U% a1 z  M" C0 q
  单链表的最后一个结点的指针指向NULL,而循环链表的最后一个结点的指针指向链表头结点。
( @/ \4 G' g( @- g/ }  这样头尾相连,形成了一个环形的数据链。
5 W6 Q) l5 J9 x+ L8 K! G; |6 V  循环链表的建立不需要专门的头结点。7 L6 t* u9 Z6 j8 b) T& U/ H
  判断循环链表是否为尾结点时,只需判断该节点的指针域是否指向链表头节点。
" Z( |) T7 l& o4 C! L$ M  八、合并两个链表的实例
* G$ P1 [% S. ?1 ?  建立两个带头节点的学生链表,每个节点包含学号、姓名和成绩,链表都按学号升序排列,将它们合并为一个链表仍按学号升序排列。) `- }  N$ Z* K; g6 t- T9 N
  算法分析:- n3 c$ H  O1 H- i
  合并链表用merge()函数实现。函数中定义3个工作指针a、b、c,其中a、b分别指向La链表、Lb链表的当前结点,C指向合并后的链表尾结点。合并后链表的头结点共用La链表的头结点。' A' h7 Z) D& v, d- \) g4 O) w
  ①合并前,先让a和b分别指向两个链表的第一个结点,c指向La链表的头结点。
3 g! @+ T8 g& p) U' Y2 z4 D! R  ②合并时应该分3种情况讨论,即La和Lb都没有处理完;La没处理完,但Lb处理完毕;Lb没处理完,但La处理完毕。: q8 ~2 }7 i% D7 e' J
  ③合并过程中应始终将La和Lb链表中较小的一个链接在Lc中,方能保持有序。" l) c: j( \& W( d. T! k7 \
; G0 F+ ], m2 J2 x0 [" v, `
: J2 }; U% n# ^  P8 S8 L
0 i9 {6 K( S; c/ J2 t- b4 `
0 w+ Z& E% ?, d' O( ]
  1.  void merge(struct stud *La,struct stud *Lb)2 w2 n4 e; z. h, ^( M

  2. 8 l: C4 P0 q  [
  3.   {
    * q) K5 R: r& B1 I" x* T

  4. " n1 W) q- `0 N& O' z/ K6 R
  5.   struct stud *a,*b,*c;& B( H7 E$ _9 s# T5 C9 ?

  6. - }) ?& y5 M& E0 m6 M: H
  7.   c=La;
    - o" n! k! t1 w
  8. # x& w9 F8 F$ O3 e4 j; ]3 h4 Q2 M
  9.   a=La->next;/* 合并前 */
    & w9 ?+ [# D* T$ M
  10.   j, y5 n& a* r- e, |3 J2 B  U
  11.   b=Lb->next;& e7 t) O8 {* C8 H. k/ D  Z1 J) a

  12. 7 O- W1 O$ e; n: [2 y$ U8 R+ r
  13.   while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */' \: j: Y! j8 q$ U7 R% i

  14.   o( ?3 r. x% g5 @  Q( e
  15.   {
    ) l  G$ x' o3 X, {
  16.   V8 t: h& j* S, y
  17.   if(a->num <= b->num)
    " A: g' @- R5 H. ]; i2 C0 ?6 x6 r  E
  18. 9 v  S# Y/ _( a4 X
  19.   {
    % h# K: S8 [, d5 M5 ^6 [

  20. . v. R( r% a: y3 H/ g
  21.   c->next=a;
    * R8 h* J7 `$ X2 J

  22.   O0 d1 Z+ K0 S5 H, }6 Y
  23.   c=a;/ w2 @# }4 ^: e0 F  Q9 L% p: V
  24. 6 @, s* H  ^7 Y
  25.   a=a->next;9 a0 D2 h# P7 V8 x5 S& [

  26. : \. k- w% o& m8 v
  27.   }
      M, i+ ^( z* K2 |) E# ^
  28. + k  s2 [  t% C# N: ^$ w$ h$ z2 ?) J" e
  29.   else- v0 t% b; X) R
  30.   Z5 P% m% G  Z
  31.   {- I8 {4 o! v, Q. F) g5 O. T1 }9 H) O

  32. 0 y% g  S) F+ r; d
  33.   c->next=b;
    6 N- e  N5 k) E# o0 \6 P7 y. l

  34. % G. g8 Z# A8 Y, [2 C0 I
  35.   c=b;& C3 N% g2 }4 C4 o6 {+ q

  36. * \- f( f2 y" p- f, y! L
  37.   b=b->next;, w2 _3 D9 X5 s& [' o$ D; w

  38. . x/ q* x6 c4 k1 G- a' i* y
  39.   }
    : d4 _$ |. T0 a3 X
  40.   T1 b' q7 j7 K$ S5 d: b9 p8 _
  41.   }
    $ c; l/ K' k1 X) h
  42. # K1 a4 z" Z, e& B* S9 M. F
  43.   if(a!=NULL)
    / A, N- Y" S7 j) I5 Y+ ~+ @, r* m

  44. , j6 }8 [5 P2 {% Q& n
  45.   c->next=a;/* 若La没有处理完 */
    ) ^3 q$ J4 M* d  v

  46. 3 N0 D  ^0 E) U& d. V6 T
  47.   else
    " m, ~5 P8 N) j5 w- G
  48. " N0 f2 \( Y$ q5 K' t7 K7 S0 r3 S
  49.   c->next=b;/* 若Lb没有处理完 */
    , a2 S- j9 \6 h9 ^  ^

  50. ) I' D! ]- e+ D3 J" {3 A( i8 d
  51.   free(Lb); /* 释放Lb的头结点 */0 M, g( a4 {  g# p8 m( E
  52.   V' w3 z% y2 |/ R# O: P8 I; f
  53.   }
复制代码

. g6 r6 g) S# Q- n6 y, E1 z/ J* j6 |( }: c, u. E# \, L/ j4 ^
) W7 p. ]( `" ^8 U/ i
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-10-7 05:49 , Processed in 0.171875 second(s), 28 queries , Gzip On.

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

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

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