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

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

[复制链接]

该用户从未签到

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

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
  1.   #include7 j) t" @' k1 d* Y9 A9 S
  2. - Z1 v. Z& V; Q1 c9 ]2 L
  3.   #include
    : \! s9 G* J! M4 S( e0 ?

  4. * Y* V7 `  [5 [" s0 ?
  5.   #include4 }. x, i9 [. }! C* e/ o$ O3 u

  6. + q8 q* I; m5 W* K
  7.   /*单向链表*/
    , g8 ^, M) }1 w* s3 [
  8. 1 h* Y! _+ h% _- [  g0 R
  9.   struct Student/*建立学生信息结构体模型*/
    9 h# {  V, b7 T  F- W$ O6 q

  10. # }: c# @$ c1 \( y1 k4 t
  11.   {
    & e0 T, b: z1 r9 e' R+ Q
  12. 3 y, [2 a7 z7 B5 c- a
  13.   char cName[20];/*学生姓名*/" Z; t6 O7 R3 s+ z& r4 F9 O( g

  14. ) A/ i( e& q6 M4 k
  15.   int iNumber;/*学生学号*/! V# Q7 h& a0 ?* D; k7 G2 w

  16. 5 p0 h0 V5 Y3 k* f; R/ p! d
  17.   struct student *next;/*指向本结构体类型的指针类型*/0 w4 ?6 m7 C6 w9 N

  18. 4 n6 g1 l$ |' ?, X1 @$ r; |& F* B
  19.   };
    5 A' w- k6 Q" g2 Q  o
  20. " C# |* `( v" H5 E
  21.   int iCount;/*全局变量表示链表长度*/
    4 s/ ^, U" c( H/ x: p
  22. % H- s$ `4 I. t1 Q4 z% Z, e% l- D
  23.   struct Student *Create();/*创建链表函数声明*/1 P1 X- U* }& |/ Z# K

  24. + ~( j0 z; W7 O0 p5 S4 X3 h
  25.   void print(struct Student *);/*遍历输出链表函数声明*/
    9 ?5 h* R" A8 v8 E7 Y+ h

  26. " F# f: f- p! d
  27.   int main()6 y8 v: N* v7 t8 M: T- _# |# [

  28. 8 |7 R3 ~6 l# b5 L" Q: j3 F, H: _" |
  29.   {# C, _8 y3 I5 X. V+ p6 ^" X
  30. % ?1 A! q$ D$ B8 d: a0 r' q
  31.   int insert_n=2;/*定义并初始化要插入的结点号*/, F/ U4 Y$ {8 ]$ y: v- V) d

  32. / q2 Y* J) n  D' h% r* v. y
  33.   int delete_n=2;/*定义并初始化要删除的结点号*/; w# d; e7 u% [2 a- D" {- [0 o  Z% s
  34. * A, W2 t8 W/ L0 w  p3 k4 C1 H! |
  35.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/" @2 C, b2 _. W0 s  h$ e

  36. 3 O& u5 H+ r' E( n
  37.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/4 D/ P0 c3 q; A( I

  38. 0 I, h1 j( W+ [  e) J& n
  39.   print(pHead);/*将指针pHead传入输出函数遍历输出*/$ c+ u3 y5 f) I. ?0 z, w7 N
  40. - H' r3 p6 D+ i& n6 T. _1 ~
  41.   return 0;# G2 e8 P2 `1 E! a$ e# t# T; s; K
  42. % k) R" s& _0 _7 s# t
  43.   }
    0 B& ]5 h9 K2 R" p
  44. . c# r+ e: q  L0 K. g1 P  V* a
  45.   struct Student *Create()1 n$ t3 h9 B. h' Q! ?

  46. 0 z$ o. ]7 ]/ A' T8 U
  47.   {
    7 @3 u1 H  C: g  [4 c

  48. ' R+ z& @" T5 i1 @* x6 U% v$ m
  49.   struct Student *pHead=NULL;/*初始化链表,头指针为空*/' A/ R$ o( R  X) p; z% U; f

  50. % p- ]* j6 M/ o! N
  51.   struct Student *pEnd,*pNew;1 l5 k: \1 f+ Y5 V+ s
  52. * a1 R3 M5 X$ H0 y8 H& q0 K
  53.   iCount=0;/*初始化链表长度*/
    & D  M  `  t- l5 T
  54. 7 m" A& T' a4 w) f
  55.   pEnd=pNew=(struct Student *)malloc(sizeof(struct Student));/*动态开辟一个学生信息结构体类型大小的空间,使得pEnd和pNew同时指向该结构体空间*/' r! ~9 t% s# r% J$ d
  56. 6 l) G' r7 m/ R
  57.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
    9 T- V0 U; K, A6 W
  58. , A! K- u$ Q. c) H% G# Q# L
  59.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/
    5 k( F2 c, |6 o2 {! }0 o! V
  60. / ]7 |8 |7 p( D" k& v. f; o$ V- U+ G7 ]
  61.   while(pNew->iNumber!=0)/*设定循环结束条件——学号不为0时*/
    . Y0 S4 a) A( P/ t. ^, e
  62. 2 z4 x8 I3 Y5 u* a
  63.   {- H. v# k/ g. b8 _

  64. ) P- Q* s5 ?/ v* v) ]8 X/ ]! s% O
  65.   iCount++;/*链表长度+1,即学生信息个数+1*/
    : a0 _- j% P3 M: P

  66. ! [" J/ k; _8 {- i. X
  67.   if(iCount==1)/*如果链表长度刚刚加为1,执行*/
    5 T. r7 c! J6 ^3 Q
  68. 1 z: p; p- {6 ^5 M! e; h! y0 {3 y# s
  69.   {
    ! f7 {) M' U7 s$ O, \5 j: [

  70. . P" \- T% p* V9 {* K
  71.   pNew->next=pHead;/*使指针指向为空*/
    ; z. X1 G1 T# t- \/ R
  72. 5 v* X  Q8 u& {3 b" ~4 W) ?4 a
  73.   pEnd=pNew;/*跟踪新加入的结点*/* u. w  ]8 y& S/ }

  74.   \; G0 \# I0 e, ?# f* I9 |
  75.   pHead=pNew;/*头结点指向首结点*/
    ! _. A6 x+ P7 ]- X$ z$ K

  76. ; u8 `6 ~. m, H) H1 Q: [
  77.   }; }9 c$ A; C# t. `
  78. + t% P+ O  p7 J' N& \
  79.   else/*如果链表已经建立,长度大于等于2时,执行*/$ u( a7 r1 s# h

  80. 3 `5 M, M/ Q" k  v! g
  81.   {0 C7 U2 r" W% P

  82. 8 W. J* K+ b" a' s
  83.   pNew->next=NULL;/*新结点的指针为空*/! h6 l2 s# _3 Z1 i2 _2 I

  84. 4 K" F. ~  B6 i, ?8 S1 A
  85.   pEnd->next=pNew;/*原来的结点指向新结点*/
    , P3 y% t! S; N6 V% x! |
  86. & i& r: \! K  p# D
  87.   pEnd=pNew;/*pEnd指向新结点*/
    * r( O- J# \4 ^! _8 \3 I& L8 r( h/ H

  88. 6 }; z) A0 T8 R
  89.   }
    . J5 n6 t* z8 K9 p
  90. - p1 n2 \6 q; q3 ^$ O
  91.   pNew=(struct Student *)malloc(sizeof(struct Student));/*再次分配结点的内存空间*/0 l8 z8 x" q  n1 [2 G+ }  e

  92. , E' f6 T6 z& R" S0 K7 V( K
  93.   scanf("%s",pNew->cName);/*从输入流获取第一个学生姓名*/
    * E! D6 a1 }' S, g# ~2 v
  94. 3 G, l- a- y2 J+ B% k* l
  95.   scanf("%d",&pNew->iNumber);/*从输入流获取第一个学生学号*/" a! ~2 ~3 j/ Q# Q4 a' N

  96.   I% D/ V; g+ c8 ~! g
  97.   }7 W5 z# o2 A( g3 C. b' ]5 Y

  98. 2 d0 y. M- w& g$ w5 p6 V/ @
  99.   free(pNew);/*释放结点空间*/: N* c$ j; ~. Z
  100. 4 [  V! h* W1 ?+ L
  101.   return pHead;/*返回创建出的头指针*/
    & ?5 i, i$ i) a) ]( J( b

  102. - {6 b  e4 a/ g/ F' I& i) m
  103.   }
    # |1 ?+ d9 [& e2 s) E
  104. ; Y' v/ D! f# U: m) ?4 a
  105.   void print(struct Student *pHead)1 A+ Q: I. K7 F8 \' P, T+ N

  106. ; c; S; L/ Y1 _+ m/ b7 y
  107.   {2 ]: y3 `- c+ L  J- T" z/ b  s
  108. 3 p& l0 y9 s; q; b: v
  109.   struct Student *pTemp;/*定义指向一个学生信息结构体类型的临时指针*/  S+ H* J4 C- I( `# S: k

  110. 7 |1 [" X) |+ a" L
  111.   int iIndex=1;/*定义并出事哈变量iIndex,用来标识第几个学生(信息)*/4 C" p7 [$ k# l: K

  112. * v5 m7 ]9 p. c
  113.   printf("总共%d个学生(信息):\n",iCount);
    5 D0 \& ]/ J, |3 E# u2 o
  114. + K; U8 V8 Z: A1 ?! c
  115.   pTemp=pHead;/*指针得到首结点的地址*/
    / [* C3 |1 @5 W) v* T8 Z

  116. 4 l% b& `6 g% R) q7 w
  117.   while(pTemp!=NULL)/*当临时指针不指向NULL时*/9 P, k; H: _  e  ?$ O
  118. - P9 V8 C8 I% X4 Z* K( ~9 I
  119.   {
    7 z5 S$ ~8 f9 K8 K& L

  120. 1 _% P- Y' V7 q: p$ L5 `. t
  121.   printf("第%d个学生信息:\n",iIndex);
    7 A  c1 I" b! z% }/ D5 F

  122. 3 L3 X, _+ D& k6 [5 A
  123.   printf("姓名:%s",pTemp->cName); /*输出姓名*/7 Y3 g% M% k) k$ B

  124. * P1 z$ N3 s! l! ^' r
  125.   printf("学号:%d",pTemp->iNumber);/*输出学号*/
    + \" ?5 [8 w/ i, m2 |& l, E( s2 h- r% G

  126. 4 T8 _% Z5 k! Q) y5 |7 e% D
  127.   pTemp=pTemp->next;/*移动临时指针到下一个结点*/+ R+ l7 p5 G  i8 X" q: i
  128. , p0 p! j6 [7 A
  129.   iIndex++;/*进行自加运算*/. R! [6 u! `. h0 P8 T

  130. - P2 V2 s8 p; `- M# J& E" D# M
  131.   }& C: i. G* v* m, N7 {5 t
  132. 0 \2 |  b. H1 Y# U- K6 D
  133.   }
复制代码
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
  1.   int main()+ S0 [3 Z5 a$ O( f  u" X

  2. - J$ y2 [- g8 v5 l
  3.   {' r! ?5 ?* l3 K) ~3 w: |1 r/ T. l
  4. , W; a) w$ m; z! A5 {
  5.   int insert_n=2;/*定义并初始化要插入的结点号*/
    & `4 {$ y) z' m: |

  6. 7 I# r/ L9 C( u- \. a/ y0 l
  7.   int delete_n=2;/*定义并初始化要删除的结点号*/" O- W$ a6 R4 l

  8. 1 j8 f; E! y% G7 ^1 t2 x9 i
  9.   struct Student *pHead;/*声明一个指向学生信息结构体的指针作pHead为头结点传递*/
    + [+ h2 N1 i- T. r, i
  10. : P9 M; S% ?6 x  v/ w
  11.   pHead=Create();/*创建链表,返回链表的头指针给pHead*/
    # p& h/ i( \+ y; {( {. M
  12. 3 n( u2 [# Z& r7 U. {' x  X/ j+ N) O
  13.   pHead=Insert(pHead,insert_n);/*将指针pHead和要插入的结点数传递给插入函数*/
    9 v$ ^2 k' {" Y$ |& J; B4 }( X# ^

  14. 9 K4 d! r/ w* Y" X
  15.   print(pHead);/*将指针pHead传入输出函数遍历输出*/
    / a" f! ?& l/ \2 E1 U& k1 I
  16. & [' K1 t. q, s4 v: Z
  17.   Delete(pHead,delete_n);/*将指针pHead和要删除的结点数传递给删除函数*// z7 {$ r( A& R5 F. w3 S% \

  18. 0 w8 O/ l* \; V
  19.   print(pHead);/*将指针pHead传入输出函数遍历输出*/
    ' Y+ M, _0 ~$ r6 ~! V$ P! E

  20. 6 d% |# a; _. t3 W8 C* F* H
  21.   return 0;. f  }( G  T$ n4 G4 c7 l- n

  22. & n: J1 D! m3 T, f$ F4 n
  23.   }
复制代码

' 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
  1.   struct Student *Insert(struct Student *pHead,int number); e( F9 P7 k* h0 [: @3 |' i

  2. % J# d' D% u* r* H  i
  3.   {) R+ y' J- T1 s+ `1 x1 z* W( I: ^
  4. ) N, r" g8 F# m1 g' L
  5.   struct Student *p=pHead,*pNew;/*定义pNew指向新分配的空间*/
    1 Y# B% _# R1 T

  6. " D: Y; t- y# [" \! @
  7.   while(p&&p->iNumber!=number)% }7 p, [7 o) K4 Z9 l0 }9 f' w
  8. 6 b5 u; X. r& ^7 q1 p( d; z
  9.   p=p->next;/*使临时结点跟踪到要插入的位置(该实例必须存在学号为number的信息,插入其后,否则出错)*/
    ) F  _* f9 d. _1 s/ W1 Q7 z2 E! p- u

  10. 4 }7 g( T5 H! N$ H
  11.   printf("姓名和学号:\n");
    , b% {$ ?' L* S# m
  12. . M" [) X3 y0 w$ |: q
  13.   /*分配内存空间,返回该内存空间的地址*/3 x! c' l% b6 S( ?  l
  14. ( K8 N9 H: H" s+ M2 \* p
  15.   pNew=(struct Student *)malloc(sizeof(struct Student));
    $ F1 b, J8 E2 _$ W3 S
  16. , {8 y; F4 `. C9 l7 M/ T1 o
  17.   scanf("%s",pNew->cName);4 P$ P; f4 H" {. ?+ z5 Z' C  l
  18. ! k+ l$ n4 Q, ]" \. Z. g! _  d
  19.   scanf("%d",&pNew->iNumber);
    - q+ t+ Q' \4 w7 M% n

  20. * W% `, T& k2 D8 o5 r+ O0 X5 Q
  21.   pNew->next=p->next;/*新结点指针指向原来的结点*/% b0 Y! E, C2 t( m7 R, Q. A+ K* m

  22.   T- I! F$ ]( Q1 A/ |4 n
  23.   p->next=pNew;/*头指针指向新结点*/3 {6 P5 i/ q3 g9 r5 K
  24. ( h* W" H9 d1 M3 V8 y2 e
  25.   iCount++;/*增加链表结点数量*/- A% ?  F" j  d7 \

  26. 5 c7 ?) |% {8 k0 M1 P- S' a& A2 K  @
  27.   return pHead;/*返回头指针*/
    " G. L# ^1 O) f7 e9 W
  28. " D4 d0 d) y  M2 I* e9 K
  29.   }
复制代码

, 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
  1.  void Delete(struct Student *pHead,int number)
    3 A( I& T6 R5 t( S+ {4 {0 Q
  2. 2 s  H5 o2 E, M/ H( Q5 `) a" t# ]
  3.   {  x% K* G- v1 z, Z

  4. . x/ S2 M8 Y. [
  5.   int i;
    * H  [: O1 f1 ~

  6. 9 n( g% ]$ P. I, p5 N+ p  @
  7.   struct Student *pTemp;/*临时指针*/0 b4 N; Z: C% I2 r/ h& N5 C' @
  8. 8 G1 @0 b3 _) K4 x* g
  9.   struct Student *pPre;/*表示要删除结点前的结点*/6 \6 Q/ h: i& N
  10. $ q3 h( }$ m  _; e# H8 I, z! r1 h
  11.   pTemp=pHead;/*得到链表的头结点*/0 ?6 F; i$ Q# E( [7 a- o& F3 r' N

  12. / g5 [7 R. h# F0 o
  13.   pPre=pTemp;
    ; `$ r+ {6 [9 Q. ~: K

  14. , v: ^8 |* `! d
  15.   for(i=0;i' C# \+ x! u5 V6 t& ]. K

  16. ) C' q  {- c! u: I! j7 o2 S
  17.   {/*通过for循环使得Temp指向要删除的结点*/
    / K" I6 N+ T: I; r9 ^9 L# J
  18. ; a+ I/ i! g# j: c
  19.   pPre=pTemp;  N8 }: v. I, e. J  _/ ]& ^

  20. % j0 p9 x2 Q8 n$ s$ ^, A4 f4 G
  21.   pTemp=pTemp->next;
    & D1 T  ?4 g( F+ Q7 x; Z

  22. % M6 E5 \3 i$ B* E' M8 @
  23.   }
    5 p7 s) r! z" D# a7 h  e

  24. * H( N1 |, `" G( ]+ I
  25.   pPre->next=pTemp->next;/*连接删除结点两边的结点*/. ]4 P5 i6 h2 t2 |
  26. 3 E! f3 K; I9 c6 j; m% E: s9 |
  27.   free(pTemp);/*释放要删除结点的内存空间*/( j( t% k. N4 G: e: c# b. A

  28. % H) {: _( A$ A/ X" l+ A! l/ g
  29.   iCount--;/*减少链表中的结点个数*/9 _2 }: E7 f2 \* H% r5 t' R1 ~9 e

  30. ' u5 h# x' Y# U$ D* O' ]
  31.   }
复制代码

- 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
  1.   #include #include# o7 n3 D' S2 R

  2. # G+ {/ W, x0 Z: Q9 }. w  c
  3.   #include6 ?7 @; i0 b: f& D, B0 e2 g8 m) F

  4. ) }* W; d6 K$ j5 C! [2 I# y% J
  5.   #define N 10
    ) F6 L/ Q+ n5 k; v2 B+ a

  6. ( R) W8 w  F3 ?/ J, O
  7.   typedef struct Node
    5 ]( [( [( e1 t

  8. - W! z, I: d7 z0 A" Z, h2 A
  9.   {
    ) {/ L/ X  m7 w: i( o, F
  10. 4 G+ [3 Q7 b% x
  11.   char name[20];1 Z1 X  n' d$ j1 {

  12. " q8 }+ V" F. J. ?. N3 u. e
  13.   struct Node *llink,*rlink;* X0 g  c/ P) N+ h" O

  14. / e) S4 n2 \) O3 c! w/ H1 d3 z
  15.   }STUD;8 o" j- c" R+ T- j- A

  16. 3 [: U  A9 }9 T( c2 J& @; H
  17.   STUD *creat(int);void print(STUD *);
    / d4 n6 b; I0 p2 W9 F6 |* p6 `* a4 B
  18. # I+ Z2 |4 C2 x' ?+ {% _( p% M
  19.   int main()" L! w/ A5 n! W1 C) V. P

  20. % p2 A  E+ x6 j5 L
  21.   {
    1 s. k( h2 C  r
  22. % x" z5 R9 b- q, d- |) r5 P
  23.   int number;% C4 N4 [8 {# C4 e. b8 h& D/ I9 A
  24. ; v0 C; P3 K* d$ V
  25.   char studname[20];4 a" m# Q# H  |$ X* x; |; _5 Y7 X

  26. - l' \+ ]  g5 k" I( [! [8 z
  27.   STUD *head,*searchpoint;
    ; S- A5 Z- J* q7 e) O2 c

  28. , Q' @0 z# z" ~4 Q$ M- P
  29.   number=N;  s* X1 e9 Z5 C

  30. 0 |4 s; E: E/ n) t) U( }
  31.   head=creat(number);
    - i0 \4 |* m  `4 S
  32. / n7 E9 n' H/ q+ T0 g; r, G& k; v
  33.   print(head);
    % y/ C9 H3 W# o  `# |

  34. % G% `. E7 S' F! @6 J+ k
  35.   printf("请输入你要查找的人的姓名:");& a- S* h, H. c7 b- k

  36. 4 }) ]4 J, p% Z' S
  37.   scanf("%s",studname);% q( n* R9 ^8 P& b

  38. 9 p7 W9 ?+ l( _% W3 f$ w  o! r
  39.   searchpoint=search(head,studname);: x) k" L$ U9 d  V7 l: v

  40. 8 v5 K2 V. C+ G0 C9 u* P
  41.   printf("你所要查找的人的姓名是:%s",*&searchpoint->name);
    - W" L0 E2 Z* C. d/ o4 l
  42. 1 k9 w/ ~( m2 P+ t/ F
  43.   return 0;8 y4 M% |& N2 @1 _( p7 B; Y! x
  44. 0 l* [2 f; {% o3 F6 L: `2 `  d; Z
  45.   }8 [. E4 s* I! E0 x, @0 q+ e9 Y

  46. 0 [2 L( M9 `- E7 J# s, [6 F( s/ L
  47.   STUD *creat(int n)
    : Q/ E% v6 j$ u# J

  48. 0 V( l& I1 B1 ^7 N( L, O! B, r  c9 A
  49.   {' ^% Q% i  x4 W" L  V1 K

  50. 0 \3 H$ @2 T, H
  51.   STUD *p,*h,*s;
    3 a2 y- X# r0 ~* Y

  52. " r* ?6 o3 S# W* I! y6 h( V7 ^
  53.   int i;0 s' x. b9 y* e. S

  54. 9 D+ Q0 O: d/ Y/ |
  55.   if((h=(STUD *)malloc(sizeof(STUD)))==NULL)
    * d& `! ?( C/ S$ f

  56. : n. H) c5 x& A
  57.   {* V: D. K, ?! M: k8 N" g' Z  n

  58. 4 G- }3 w% l" I, r- W- `+ [' W1 {
  59.   printf("不能分配内存空间");
    3 h9 r- Z( Y4 h0 a# `" Y5 T' N% u
  60. ' C! E8 y8 h1 Z3 k7 E
  61.   exit(0);
    ; u1 z3 A" v' x
  62. # ^! _7 o0 T4 H, }: f* h  |
  63.   }
    & H% I; f5 X4 W. U1 ?4 m
  64. 0 u1 R4 k2 {9 G
  65.   h->name[0]='\0';
    2 u8 E9 X' b  B' h7 M
  66. ( Y" B' _  w) y4 M# n4 [- F, Q
  67.   h->llink=NULL;. ]2 d* c, q. `5 b% U9 B
  68. ' [7 g1 V: E% s. y% `! X9 U( U+ Z
  69.   h->rlink=NULL;4 k9 }# G9 m. Q% k$ v3 b
  70. 6 G  v1 {5 Z2 F% p% U8 m' l9 Z( {) {
  71.   p=h;
    9 g: S: S. g' b

  72. ) E4 o9 @6 i% }; _7 j
  73.   for(i=0;i0 x& {# \% |5 q. J, s, y% \

  74. 7 T; V& a* B! O: z3 K  U
  75.   {
    ; d' F8 R6 N) }/ z

  76. 5 R7 _6 O7 Z0 p6 {0 I2 ?/ ]
  77.   if((s=(STUD *)malloc(sizeof(STUD)))==NULL); C5 ]2 }  u) J7 T" i
  78. 8 F, i# ~6 E6 T- L6 Q" q
  79.   {: K, {8 \& G  k% e) ~/ j) f

  80. $ W/ Y6 ^& F3 c- R2 U
  81.   printf("不能分配内存空间");& {9 v3 F$ F8 i, E, }/ M8 b; ?

  82. 6 R! ^% ]' |: g1 Z% e; |6 O
  83.   exit(0);
    * k+ D+ ?! G! `# h6 x

  84. $ l9 t/ _% l! q9 ?3 t3 m
  85.   }
    7 i8 `8 a. S7 ~* a5 W

  86.   E, w8 `* @& |5 N
  87.   p->rlink=s;
    . x3 Z& a; l% y" M
  88.   B0 b7 H1 \( ]& d" h
  89.   printf("请输入第%d个人的姓名",i+1);
    ! d* U0 h% b8 D- H

  90. - B: i# \% A8 m6 @% Z
  91.   scanf("%s",s->name);
    * u9 H- |( `" {  c; l
  92. ! n5 _& n) a  C* ^/ K- E0 F" q
  93.   s->llink=p;$ A& ~0 J- U; m1 c. g

  94. 4 w. e" p* g" |& T- x& h
  95.   s->rlink=NULL;. @& k- f, E; Y3 }
  96. 7 E( E( E1 F4 ]
  97.   p=s;' u/ y' Q1 G4 Q0 g
  98. 1 o( u3 D9 a- d  Y: r
  99.   }
    9 c+ ~+ ?( n2 E( f

  100. ) E2 C+ R' y! ]' l' ~/ `
  101.   h->llink=s;
    % _% ?/ `0 g1 s- E3 n$ q
  102. # |& L6 W1 U8 B( w
  103.   p->rlink=h;" }1 E3 x1 ]% D/ E8 }9 ^

  104. $ s2 H+ k) W1 S/ F7 G
  105.   return(h);
    / f( @) {; N$ y, F) P8 k5 W; o

  106. 5 l, W3 O1 U+ x8 E1 m
  107.   }void print(STUD *h)
      L" ]8 Q6 l. }+ f; Q
  108. 0 x1 N4 G5 A; n+ E; X& t( j; K# J
  109.   {1 \6 ]: \+ m8 ]. s! x) h9 Y$ A

  110. 1 u$ L  W% g3 W& b' P
  111.   int n;
    1 R  `* G- B0 C: `0 O# l: B: I
  112. , `0 o' M; Z9 I% J8 a6 c# H; o
  113.   STUD *p;
    8 \: t0 @3 s) j# E# l2 J, I+ y7 c% A

  114.   b% X9 e  y% V; b: ~& y* E  F
  115.   p=h->rlink;+ _1 W# i$ Z% E, ?- Q" \3 O+ e

  116. : D# I. O3 R7 x! R
  117.   printf("数据信息为:\n");" N; b; h8 b" K# a

  118. 3 ?$ G) U0 H$ ]
  119.   while(p!=h)- [* D- J* Y% E
  120. 8 h! B6 q6 ]+ V! e9 P/ v/ Y
  121.   {# W" k& c- q( g9 v
  122. & u, I/ x& E: Z: z( ^( U7 A* d/ E4 B
  123.   printf("%s ",&*(p->name));
    3 r! X3 ?" C2 _8 K3 a6 ~
  124. 5 P5 c1 T( q' n
  125.   p=p->rlink;
    / a; H( X% A$ i

  126. $ u/ R. h* \# E
  127.   }
    & C. O1 a) n: g% |; {

  128. : }" V! W2 J# @: a  v# }& I9 r
  129.   printf("\n");) ?# D! a9 R" j2 X

  130. $ f- l& o0 m& O5 f! }
  131.   }
复制代码
* 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
  1.   STUD *search(STUD *h,char *x)
    # x# D0 D. N# V% v* _

  2. 6 n' h$ D5 H: d8 R1 n% c
  3.   {3 t' q+ T. k& t$ N; w& C
  4. $ @9 W$ `  {6 r# ?
  5.   STUD *p;9 p- @$ `9 i- R' y7 y- _

  6. ( `, l0 h  u- m* L' W1 [$ v" S
  7.   char *y;) m% [/ Q+ @' F! F
  8. 0 {4 T7 I5 R% B$ f% C/ W. V' J1 A
  9.   p=h->rlink;
    # I& T( d3 L# j8 u7 N: D6 ^  q7 l; J, i
  10.   k4 ~* Y1 A' o
  11.   while(p!=h)- L! [; w7 W& b' y' T2 |( h
  12. / _4 P* {7 m% ]; Q
  13.   {( y$ E) T5 J/ f2 K* R5 I$ Q' E

  14. ) A0 {5 y5 s8 j( B
  15.   y=p->name;- |7 G: G/ P" j  s/ X  A) w7 L" z
  16. " c( C% a1 X7 i
  17.   if(strcmp(y,x)==0)
    . ?. b7 _0 v' n& n- {" F- r9 I
  18.   y# |; s7 X/ L2 B
  19.   return(p);! k  i0 W4 E  ]  p; H% |

  20. 5 w4 s3 l3 `- b' l/ i' @0 q
  21.   else
    8 J' Y3 ~4 r% `& S" V
  22. 4 A* ^; p% B0 @- `6 t
  23.   p=p->rlink;! |% u( _. ?2 Z, C0 u5 w7 W, q

  24. : v( m8 d. J5 P: A. T7 a6 ~& Q
  25.   }, Y) _' T5 o8 j2 l( p- {) x9 J

  26. . x- M/ U& |  y" D4 K. z
  27.   printf("没有查到该数据!");
    ) X( B" G- A5 S+ m! v. a
  28. 2 n" y4 B# r1 Q+ C# V2 n; @+ `
  29.   }
复制代码

& 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
  1.  void merge(struct stud *La,struct stud *Lb)$ n: f# ~4 L0 m7 P* e7 m
  2. " F4 m2 l3 i3 F
  3.   {  E6 }, a$ M. @; F

  4. 0 n8 _0 p8 Z. n5 f) P( a7 ?
  5.   struct stud *a,*b,*c;* {# d- E% _# f, ^' D9 p7 m

  6. % `/ u2 _: g( t9 p
  7.   c=La;
    1 y+ ^8 e% o  D9 p/ V) N

  8. : l# g/ o* G* t2 E; b9 \
  9.   a=La->next;/* 合并前 */
    0 [0 H. k. I4 B. u- M+ C+ X( Z5 @

  10. ) ~, O4 H( E1 t' g& Z: g) r" ^
  11.   b=Lb->next;
    7 e- ]3 J/ A6 M2 y$ }. a9 P8 M; D

  12. + K& `# h; {: R' n
  13.   while(a!=NULL && b!=NULL)/* La和Lb都没处理完 */
    4 v6 D0 ]9 k& X/ h
  14. ) J7 J4 ^9 {+ B% e& G
  15.   {% a( T) t" N5 \2 H, y* k
  16.   W4 S9 J6 `8 [/ Y
  17.   if(a->num <= b->num)
    & Q+ I1 f, V! W1 p
  18. 4 K; I+ s0 r: z" M
  19.   {
    " c6 `0 k4 C5 \6 H
  20. 8 i6 z8 }8 [0 z9 S
  21.   c->next=a;
    8 z1 u$ R3 z- }% a( b

  22. , x) }! x. w, m5 b9 D8 |
  23.   c=a;
    0 k2 \* [; u' X3 h  x5 \  l/ e
  24. " k9 P1 ]/ k! D( |+ k
  25.   a=a->next;& m4 B3 K9 l, [6 ^& ^
  26. 2 \$ M- O% @5 e+ d; J3 Q
  27.   }8 D; Y( |6 l! F1 j
  28. * W9 l: w( G, H1 T: y% p
  29.   else8 v# \( S! H; t% I4 w4 n+ a
  30. 7 p3 m) w: F4 @
  31.   {+ k- _7 ~6 J" o0 f
  32. ' ]6 X) f# o5 P3 h* W1 R% B+ ^  [, B
  33.   c->next=b;
    - X! M5 Q3 [/ @# W

  34. / ^! b; t4 S8 C8 P. Y. x/ @" |: ~
  35.   c=b;
      [2 Z  O6 v9 Z& G: e: J" e
  36. * V/ `9 ?% ]+ _) T- N
  37.   b=b->next;
    ) u0 @) W& l% ?3 A

  38. 4 Y1 X2 ^5 {0 |
  39.   }% y& l- D, V" Z
  40. + X2 B7 p; \) ^2 E2 Q- @3 x* k
  41.   }
    * O! w5 i/ b& p& J5 i9 O
  42. ( l: U& b6 n) c& J! o1 B
  43.   if(a!=NULL)2 O7 j, P, j) x! ^
  44. . a& z$ ^( q! Y' s+ Q( n' B
  45.   c->next=a;/* 若La没有处理完 */
    - U" d- L( q5 y  u

  46. 0 V  }8 a" _* k5 T, m6 Z( }
  47.   else
    7 E& ^. j3 ?: l7 x- Y

  48. . {# |+ L3 L  w+ t
  49.   c->next=b;/* 若Lb没有处理完 */
    3 _) e3 h8 K; k( w" L
  50. ! f- a$ [1 j8 r; k# v
  51.   free(Lb); /* 释放Lb的头结点 */4 _' \8 l/ @3 p( ~+ @

  52. 9 _* z0 Q% J& b  F. C2 Y
  53.   }
复制代码
  ]! s1 d6 A. P- x! X

4 o" i# j1 F+ L! `9 _; y* V1 m* [+ g) c/ l* J! c8 b
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-8-19 23:54 , Processed in 0.140625 second(s), 27 queries , Gzip On.

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

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

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