数学建模社区-数学中国

标题: 【Java演示】什么是链表?数据结构 [打印本页]

作者: 杨利霞    时间: 2020-5-4 15:55
标题: 【Java演示】什么是链表?数据结构

: i( F$ B2 ~# m; y3 F; D- ]$ U【Java演示】什么是链表?数据结构
3 v$ A+ X: G# S0 x6 V. m& Y一、单向链表- _4 H$ C0 f7 w9 o& w4 ?3 p

( [. a, c$ i, `* l) { 1.png 9 s: N+ p  K- I) E& z( \
链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。9 |, h$ j! p$ m5 H0 s$ W- b
单向 链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。5 S* c) B% w- [' B6 d) d
链表的第1个节点被称为头节点,最后1个节点被称为尾节点,尾节点的next指针指向空。+ M' c. N- n4 `7 B: v+ c9 W- m
0 v9 Z: E' ^' n2 {
什么叫随机存储呢?# X1 I/ Q" d! K# M" u3 z) i
* H0 F& J# Z  r: Q
如果说数组在内存中的存储方式是顺序存储,那么链表在内存中的存储方式则是随机存储 。
( K  l: [( I2 v2 i0 U  g上一节我们讲解了数组的内存分配方式,数组在内存中占用了连续完整的存储空间。而链表则采用了见缝插针的方式,链表的每一个节点分布在内存的不同位置,依靠next指针关联起来。这样可以灵活有效地利用零散的碎片空间。+ I' z( T/ [9 i0 H% R
3.png
/ O; n" X# e% v- @" S) \: E/ B$ e& {/ ^" ?" M4 s0 ]# D! f, r4 m

图中的箭头代表链表节点的next指针。

链表的基本操作1. 查找节点

在查找元素时,链表不像数组那样可以通过下标快速进行定位,只能从头节点开始向后一个一个节点逐一查找。

4.png ) `3 U" n- g3 z% p0 V4 }6 e
: X8 {& `# B2 W! G$ I
/**
) w& S  C) w0 H6 w, @+ D/ X     * 链表查找元素; R( q3 \5 V0 D! o0 |& `
     ** R( @4 \+ u0 I
     * @param index 查找的位置  \' B& D/ ^) ^" J6 k
     * @return index位置的Node对象. }' {8 _* b8 m, P: Q& h) H6 q  ]
     */' b9 d& m4 \8 ~7 t! |! f
    public Node get(int index) {+ h/ n' i5 h$ @4 A6 l" d; M
        if (index < 0 || index > size) {8 D2 A3 {( R# A: P, ?+ l  @
            throw new IndexOutOfBoundsException("超出链表的节点的范围!");
( l2 e; m3 r/ _        }
) `+ a3 n; J: E7 E* g1 D& u" {        Node temp = head;! x- k, U% X8 O( M& j8 _* U5 n
        for (int i = 0; i < index; i++) {
/ _  t1 U# c. m8 ]7 |% w            temp = temp.next;0 {7 V, X" O: g' r: G3 o
        }3 W9 u" V  @. l* `. g- J5 \# E
        return temp;
- ~2 F- W1 y2 t) g5 ~! r7 A    }; X4 f: T- ?7 d1 t9 L& M) E- \

! u: ?) D: |# q  q; D

链表中的数据只能按顺序进行访问,最坏的时间复杂度是O(n)

2. 更新节点 5.png
, W: }& c/ L2 a. ?: w- B
( ^" F9 g  G! H& B) u7 `如果不考虑查找节点的过程,链表的更新过程会像数组那样简单,直接把旧数据替换成新数据即可。+ q* d: Z8 i5 ~, ?% R* _) l
如果不考虑查找元素的过程,只考虑纯粹的更新节点操作,时间复杂度是O(1)
! ]  |: e- N1 N7 k/**
) {4 m' X7 Z) M6 e1 _     * 更新节点 将列表中指定位置的节点的data替换为指定的data。
3 h8 @& H: J* L" t% b$ {     *! T- V% x$ j: g. |6 G+ w5 ]' t
     * @param index 需要更新的节点的位置9 A2 t' q% L, @2 u' U$ }
     * @param data  新data
5 Z0 @$ ^0 y1 w# D8 t$ p     * @return 旧data1 @! ]/ _9 a; l  u* i* y
     */, U- t/ `/ L! j3 Q- z
    public int set(int index, int data) {
- n$ G& ~5 Z5 y. b/ p: @9 o) s        Node x = get(index);
3 U3 T. ~& b/ |        int oldVal = x.data;7 M% {9 m% {9 t) u0 L9 l
        x.data = data;
$ \  Q- R1 v. _. B" r        return oldVal;6 j( l$ S7 c4 W( V: ~" W- m4 Q
    }
7 B- b# i& c$ E! R. a
4 G' O# B4 R; O$ v* l' ]2 g' b8 k3. 插入节点

只要内存空间允许,能够插入链表的元素是无穷无尽的,不需要像数组那样考虑扩容的问题。

与数组类似,链表插入节点时,同样分为3种情况。

3.1. 尾部插入

尾部插入,是最简单的情况,把最后一个节点的next指针指向新插入的节点即可。

: y: g/ |! ~: ^4 v
6.png , G1 y4 h* `2 {& G
3.2. 头部插入

头部插入,可以分成两个步骤。

7.png
+ O/ A6 S( M& b, o3 U
6 ^/ F: k# d4 L* h3.3. 中间插入

中间插入,同样分为两个步骤。

8.png
5 d1 ?% }3 _9 T; k. Z" n" _) X; L$ i. b5 L2 ^, C) N+ n
三钟情况的代码合到一起4 Z& D5 Z$ Y4 i; q8 e  w, S

7 n6 ~. c+ u% ?. ]/*** b; K4 D7 {  a$ p+ G% I
     * 链表插入元素+ g) _4 |- Q) n; {
     *
- O5 I6 y3 |) l: G     * @param index 插入位置
0 S# f3 L  k! F1 h0 A     * @param data  插入元素 被插入的链表节点的数据
- v# q5 O* `" i/ }8 u     */
1 R0 b8 q: Y3 w- g* F& F    public void insert(int index, int data) {
: h2 f3 G7 N0 x! y+ F        if (index < 0 || index > size) {0 }* |3 p& \  ^# n% l  p0 i  [; L
            throw new IndexOutOfBoundsException("超出链表节点范围!");9 q8 |1 z9 x/ e- U
        }
( B0 E0 a- F- U) S        Node insertedNode = new Node(data);
" r9 t, w7 ^$ b9 `( F        if (size == 0) {. ^3 O, h8 [  J' }$ {
            //空链表; V, K5 g3 ^, t4 \& k: r4 k
            head = insertedNode;
* s7 {( v0 z( D6 q  `! d$ l9 H            last = insertedNode;# W$ x8 T5 n3 b5 c7 D) g! X! h
        } else if (index == 0) {
1 B& o) G4 D# d2 n# G            //插入头部; a+ B  i  O  W, C$ y
            insertedNode.next = head;
. C6 e9 j/ l0 K+ W, d            head = insertedNode;% `/ T- O: r2 P! r  A
        } else if (size == index) {2 F0 x2 }1 T2 P$ x
            //插入尾部. }7 F+ s! S0 [( m9 \3 O. j
            last.next = insertedNode;& F" u& q, j& b
            last = insertedNode;
! i9 ~7 }, m% \& q% H2 ]        } else {
; a+ x8 S1 y4 N5 Y) H            //插入中间
& H# O: O# n: q6 M            Node prvNode = get(index - 1);
  \1 \2 D) Z5 L) K( Z4 z( y2 e            insertedNode.next = prvNode.next;/ y9 U% `2 _' X; e( a9 q
            prvNode.next = insertedNode;
3 N: y* J1 ~+ E; j7 B; S3 j! n        }
0 f9 F# A' @% |1 v. @7 e+ E6 `        size++;
) U+ C6 u+ K/ ^9 ^: E: u1 }    }
( B1 A# ]- {/ ~/ H5 z# u6 h( g) k3 L, U7 B, L4 }& m
/**
  |/ K8 T+ h# G5 V/ s     * 链表插入元素8 g9 J# ~* {3 W9 t# c7 h
     *# c6 H& Y8 A8 U8 w4 H) V& Z
     * @param index 插入位置7 V1 Q5 G) t- G0 B  \# u* Z
     * @param data  插入元素 被插入的链表节点的数据, r7 I6 R! z6 Z  W; w% [% \
     */
9 @! B# [! F8 s: c0 ]2 W    public void insert(int index, int data) {1 q% b6 Q/ F* i% M6 h$ x6 e9 h4 _4 x
        if (index < 0 || index > size) {
7 ~8 W5 S, S/ e) F            throw new IndexOutOfBoundsException("超出链表节点范围!");
; ^/ h# b) f3 t2 k        }' h' O0 n' |$ W4 v$ ~! A! N% `
        Node insertedNode = new Node(data);
* [! w1 i1 m8 c        if (size == 0) {0 j% e. I0 [& \& X
            //空链表
( i8 i; z0 h8 P- V3 r+ @7 t- s            head = insertedNode;
; G& A+ w1 ~2 c( `/ u3 R            last = insertedNode;
/ G' ^- ]$ M1 o8 k! M. F, S& z        } else if (index == 0) {! j6 S! B2 j% {' U( {) _7 N
            //插入头部3 }( `. p- E. j0 }& C* a" K
            insertedNode.next = head;
0 ~' l* N' ?) a, T) E            head = insertedNode;, d8 |) A" [6 u4 P1 B3 n
        } else if (size == index) {" U6 m+ F! t7 N# S% @
            //插入尾部
( a7 k( J) t5 a            last.next = insertedNode;
4 Z0 G# Y2 Y! ?% M  {            last = insertedNode;. A3 |; M4 t% w5 r
        } else {& x' M5 e& w: g! B7 I" o
            //插入中间/ s0 ]0 p) i- Z& f8 d/ `; ]+ P, S; T
            Node prvNode = get(index - 1);
$ N7 r4 Z: J2 z+ r. G% I# C            insertedNode.next = prvNode.next;
5 h; M' F* ~' A            prvNode.next = insertedNode;4 I1 e1 U" a  e+ f5 R4 l; n' x, [
        }6 j: }" T! o( a0 B  q/ @& J+ r
        size++;0 v: T# o( A; Q& k
    }
' Z1 A2 V* }5 K. y. e! D4. 删除元素

链表的删除操作同样分为3种情况。

4.1. 尾部删除

尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即
0 Y3 o( ~$ I1 b) O5 `& r可。

9.png 6 h2 j) ]# }+ R! k  [, I; F+ D
3 \0 o7 @5 e( @: z8 B/ R
4.1. 头部删除

头部删除,也很简单,把链表的头节点设为原先头节点的next指针即可。

10.png % Z; [6 x+ U& m8 V) W& E; l# g2 Q
: I- Z( Q' A2 Z% K7 ^0 R, F" z
4.1. 中间删除

中间删除,同样很简单,把要删除节点的前置节点的next指针,指向要
+ u* s8 o; F/ b, f删除元素的下一个节点即可。

11.png 2 w$ ~# n+ B6 P: y9 M
6 ^/ n- _8 A- q+ ]+ G8 ^/ e! J# N
* V! x0 V8 ~) N* t
这里需要注意的是,许多高级语言,如Java,拥有自动化的垃圾回收机制,所以我们不用刻意去释放被删除的节点,只要没有外部引用指向它们,被删除的节点会被自动回收。
" Y  O  o  }% d如果不考虑插入、删除操作之前查找元素的过程,只考虑纯粹的插入和删除操作,时间复杂度都是O(1)& x: `- E' {1 l/ Q
/**
$ o3 J" @7 h; a( X/ P' b     * 链表删除元素
' E9 f" F! j) o8 q! C' A5 Z/ o     *
& n6 A8 a, R, |% Q& Q; K4 W" w     * @param index 删除的位置: M1 C& w, [3 j
     * @return 被删除的节点1 T9 j. P5 `' a% E1 {, {& S
     */& W8 [& P/ G3 Q  H  r0 t
    public Node remove(int index) {
. |7 Z1 n( A3 ]$ r        if (index < 0 || index > size) {1 D0 T3 o8 i6 s  @4 B
            throw new IndexOutOfBoundsException("超出链表节点范围");. {1 z# N9 _' d! E" {* {5 ^6 F: A
        }6 o& [" s  d' R& p/ o! V; z0 M6 v0 k
        Node removeNode;
4 W) T7 @/ o( L) X% v1 c- Z6 z# _        if (index == 0) {
7 n" A+ l0 j7 a& i% j1 s# q            if (size == 0) {
" `5 b% F8 p7 K3 X( N2 c                throw new NullPointerException("当前链表为空,不可以进行删除操作");5 P9 _) I' T1 n. M5 A) U& p3 c
            }0 R  u$ s' m8 ?* t
            //删除头节点* J/ U! i) T" D% N
            removeNode = head;
. k! A& U6 a8 q! s; R5 O) P; g; g            head = head.next;8 {; A/ h6 G' e9 _# v, e1 s
        } else if (index == size - 1) {
+ L& r, J* @( ?; y            //删除尾节点
5 i# {+ ?' Y# K7 |* |$ H            Node preNode = get(index - 1);
6 Z* M8 O2 c$ Y; P+ i6 }            removeNode = preNode.next;
9 _& k3 w. o: {! d; {5 w3 \: K            preNode.next = null;' B, R& P" }/ d: O: \. ]
            last = preNode;
0 C$ S% p( F5 S7 G" \# {1 S. H% y        } else {
1 g  @3 H% p' |            //删除中间节点) K( `8 z( a3 B% s" w8 Z
            Node prevNode = get(index - 1);
3 M6 [/ h8 @5 A/ l3 \            removeNode = prevNode.next;
9 k1 V0 ]/ l9 ~0 _            prevNode.next = prevNode.next.next;* O5 b* k5 Y# H0 Y9 j" p0 v
        }
" v# z: r5 E1 }4 K1 f        size--;
3 w) a2 k5 s7 `& V9 |, O4 A        return removeNode;
  Z$ ^: s0 M  |. h+ J    }
5 I$ Y; u/ {$ V9 u; IJava实现链表的完整代码package chapter2.part2;, u! B, w& C/ G& I
0 g% F) ]9 j- Y4 M7 q" E7 P" l% r
/**; U( q4 v* k6 R
* Created by IntelliJ IDEA.5 @- o0 H/ u) K
*) ?* |# t$ z, `7 n+ Q9 @
* @Author: 张志浩  Zhang Zhihao2 ^/ g3 y/ P# o/ E. `* h
* @Email: 3382885270@qq.com
7 W, {3 _) _( t  K: n% x* J6 w * @Date: 2020/5/3
8 O, T- D1 F0 z1 Y0 y! y4 w6 J, E * @Time: 13:396 a0 K- w8 V. l) I8 T, m! b
* @Version: 1.0
! o) U' T9 E! p, U6 a% E! K! N9 H */
5 z# X$ v2 a8 G$ l/ t; N3 O' Kpublic class MyLinkedList2 {/ B) u- V. q+ }, a3 E6 ?
    private Node head; //头节点* b2 B- [7 z- _
    private Node last; //尾节点
/ d/ h9 u2 X, X& z& [    private int size; //链表实际长度
5 {6 p2 R4 h" `# z
# q; O3 ?1 @& m- Y# V5 G- v  V    public static void main(String[] args) {
- M4 ^- {4 X8 J+ a: k5 V4 S! F$ `        MyLinkedList2 myLinkedList = new MyLinkedList2();* g. e$ G" P6 m( F) ~' ]) a+ e
//        myLinkedList.remove(0); // java.lang.NullPointerException: 当前链表为空,不可以进行删除操作
7 [4 A! \: P' a( l//        myLinkedList.remove(3); // java.lang.IndexOutOfBoundsException: 超出链表节点范围
( h* o/ i& W" F6 d& d8 H& D: o* u        myLinkedList.insert(0, 3);
7 l) D( y3 D2 c& O        myLinkedList.insert(1, 7);, T% K% X- q( j
        myLinkedList.insert(2, 9);
& F5 U( N2 W: ]% P5 B        myLinkedList.insert(3, 5);
2 y) l5 [2 f0 }7 T4 g        myLinkedList.insert(1, 6);
  j  P3 @4 t3 H2 E        myLinkedList.remove(0);, W& Z8 |3 l2 P% L3 K( n. P9 r
        myLinkedList.set(0, 23);
- \. y; m- f: z( O1 G        myLinkedList.output();
% `8 D% X# ?8 i. @8 M/ ~    }
7 l5 R. C3 |' u) d( \
5 x6 M. \8 Q- @8 d; u    /**3 X$ z5 i" h/ j" S. ?( d* c
     * 链表插入元素
  x( j+ Q- n3 G2 Y! v     *
; K2 m! p/ ]1 o8 Z     * @param index 插入位置
$ r$ H. `! f9 }( l8 q     * @param data  插入元素 被插入的链表节点的数据
0 q; N' _5 T  E5 h% z! p1 K2 I     */
* h; _$ Y; Q/ [& B& d# g    public void insert(int index, int data) {
* C- a0 [/ y) o+ N. z$ c        if (index < 0 || index > size) {
! Z/ D4 u. \$ @( y( }+ f            throw new IndexOutOfBoundsException("超出链表节点范围!");1 m4 v% g, }7 H& s+ k1 a5 X
        }
9 c# G6 r" W) g  M+ W, e        Node insertedNode = new Node(data);5 v) q4 d7 K$ ]8 z' S
        if (size == 0) {+ ]" e  a% D0 }
            //空链表# e7 ^: Q- J* P: Y6 u7 C
            head = insertedNode;
8 S- i$ `7 ?( s( N1 e            last = insertedNode;
3 \: C+ }) b+ ?        } else if (index == 0) {) l4 K+ C& o, s+ {2 v- q1 f
            //插入头部% ^& q: A$ r9 t* ]7 u
            insertedNode.next = head;6 i) I( w3 [4 h$ r3 g
            head = insertedNode;& n% H1 l7 I# Z6 O- f4 g" [
        } else if (size == index) {2 z7 r  z2 O, k1 H8 S& R
            //插入尾部
' R) ~2 F; E9 L+ s' v% S! W3 x            last.next = insertedNode;- o! U8 k1 G3 j6 n+ o" _# L* X
            last = insertedNode;5 ^7 M6 W5 L( h- F( E
        } else {! A- l; F8 ]" M
            //插入中间
3 b5 W0 E0 T/ o, }+ \! G9 O! k, ?            Node prvNode = get(index - 1);' s( e" i0 U% W* w0 z3 |
            insertedNode.next = prvNode.next;4 W9 l9 E9 w( k1 p" I/ F
            prvNode.next = insertedNode;* i1 N, G* z; A6 H( @; `# {. l
        }5 }5 [: Y! e% S/ |* u! \, R' z7 S
        size++;; _5 }6 a4 d; t; T$ w
    }! g  F3 ^) `; y

$ x+ z7 N; ~( R( w$ P    /**: Q+ y- j6 E# j3 m. q" |
     * 链表删除元素7 A: \% _2 b: A9 A, |" |: A
     *
9 C4 S' f" A6 h& W1 j1 ]     * @param index 删除的位置3 D; l! y8 ^" x  Y
     * @return 被删除的节点" ^2 R# l$ |$ T9 N+ q2 r( Q
     */
1 W: L: x# i* c; F    public Node remove(int index) {/ r& q' |5 a: p' w5 A! Y% W
        if (index < 0 || index > size) {
. Q5 k+ J; f$ p- f. r* Y3 a' l( [            throw new IndexOutOfBoundsException("超出链表节点范围");. R  y  Z  g/ H' u) T$ G
        }/ b4 o: K& a/ l* ]! W: W' M+ K
        Node removeNode;: j) w6 N0 m! z
        if (index == 0) {5 i( ?, P  w+ F! }: Q6 M; j4 f, \
            if (size == 0) {0 u9 `0 G6 J5 @- Q
                throw new NullPointerException("当前链表为空,不可以进行删除操作");1 A% q' X) ]2 w2 \8 S
            }! n5 ?9 |- ^2 r) N
            //删除头节点$ Y+ }0 ~5 y/ {) S) w9 Z' P
            removeNode = head;: ]  d4 J4 j8 m: Q2 Y: C
            head = head.next;6 u' W1 d6 z& I; E1 C3 K& G
        } else if (index == size - 1) {, S% Y( n0 f1 J0 T+ B
            //删除尾节点
' N3 k+ F- M0 O1 Q% K+ \/ N& G: ?            Node preNode = get(index - 1);# s) D* D1 e' s$ j2 A
            removeNode = preNode.next;
' M0 S5 P) {4 t+ ^4 F            preNode.next = null;
9 |7 b$ K: k5 `6 H! F            last = preNode;( `+ J; C& k( n" h
        } else {+ s) a  [- f9 A8 w
            //删除中间节点
( d% C: y6 A) i: V; b' L            Node prevNode = get(index - 1);
+ E, P! Q2 r  o2 x            removeNode = prevNode.next;
; v4 c2 b" r! K- w) ~6 T$ y' ?            prevNode.next = prevNode.next.next;
( W8 [; n& W0 r! @6 a        }
: S8 U7 |% ^' a. H! g% Q' m# b        size--;$ c" M* G+ d  k) i8 j
        return removeNode;
( u4 e3 x( E6 ?" U& o    }; a- j- w7 p: [0 t/ H- S
8 o' J* [# n% z* e3 V% e4 Y
    /**  L# U9 Q% j6 l6 L$ O2 f
     * 更新节点 将列表中指定位置的节点的data替换为指定的data。
! e0 I( d3 Q+ @7 x: j     *
* R5 E, F1 V) h. T     * @param index 需要更新的节点的位置& E0 m$ l! `" F9 ^' \# p. o
     * @param data  新data0 G8 h3 j- s1 \2 `5 L8 o, p$ {
     * @return 旧data
4 c2 W" D5 O4 w1 H$ ^. S# Y     */
0 a5 F) P0 U/ b& D) G9 C; h    public int set(int index, int data) {9 l  a* \( O3 ?0 A+ w6 u& U% }
        Node x = get(index);( c/ B0 U4 G& k, b! q. T
        int oldVal = x.data;$ J) w" x5 J7 C4 D$ c. [: R
        x.data = data;' Z: _) [( p% L, ]8 D
        return oldVal;
% ?& i7 |2 q( x, u! r' [% E" h    }
. |7 `, @6 O/ P7 o* f! a2 r) w1 @# `; @  `, B  \4 `+ @
    /**; O- D& l7 P. L: g: [% P
     * 链表查找元素
' v1 O% R8 _2 ]! _     *
7 J6 |. X- S1 R5 }$ z4 Y) h7 n     * @param index 查找的位置
9 r' Q5 M; o8 E, g7 V2 X' w6 a     * @return index位置的Node对象& x# H' x$ S8 T8 x
     *// C3 h) o# b5 V
    public Node get(int index) {5 a+ g- s/ V; T) a, w& }
        if (index < 0 || index > size) {- K7 K: U8 N' T& n) X& d; {/ _
            throw new IndexOutOfBoundsException("超出链表的节点的范围!");8 |7 g5 U0 b0 K
        }
0 \9 ~( m  y8 U        Node temp = head;9 D8 e/ H1 j' F# T! J
        for (int i = 0; i < index; i++) {8 x0 K( n9 g, [8 P
            temp = temp.next;- e/ r" X) N; ^5 C$ O, r. g
        }0 C3 F. Z' P- z% l
        return temp;
. ~+ {: H2 I& b9 b    }
6 r, X0 w5 a# T& i$ E3 C5 V( Q6 H# g  F1 ^9 ^. S
    /**
: @) {5 i% }  J/ H$ E, h% d     * 输出链表
  m" Z6 i, @- j     */
" a9 g& W4 V- J5 _4 m- L1 ^    public void output() {
2 L% i1 D0 G3 L. \        Node temp = head;
3 W4 ]0 f; R! T2 Z9 ^        while (temp != null) {( w7 T5 |8 L* i# U; B1 C( L* P
            System.out.print(temp.data + " ");$ R; {% t2 T8 v# L
            temp = temp.next;' q  W; N- @: h5 n9 `0 g7 I
        }! z0 a8 D! M1 m1 b
    }8 N1 P/ g7 \- \$ S+ R  D

+ }0 c0 P; {9 T. r8 f+ _    /**
8 J& w4 e+ l, |$ \     * 链表节点7 c; x  a/ h2 O) a
     */2 N8 F) z8 h% q" T  J3 e; l
    class Node {
+ p  h( m0 Y8 i2 e- j! I2 R        int data;- @$ c9 F. G5 F4 @
        Node next;
, S& `% ]& E5 ~8 N1 |- o1 Z$ c3 F' Q
        Node(int data) {
, L# ~* R' F% r) y- O# @            this.data = data;: h: e3 j  U, g3 n( v6 m
        }
  m8 ?% l  n- |' o    }
7 k1 ?8 x: K3 J& F1 e}$ B1 }1 ?4 J3 x
9 |; |- t6 q' b0 `
9 r$ u* ]9 [9 E
二、双向链表 12.png
" Y  ^/ v9 q! z4 \双向链表比单向链表稍微复杂一些,它的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev 指针。
$ f& g8 A3 Y' u! f0 D& v8 R, u; Z, L. s1 K6 {3 z+ Y. P

% S  z: I# w' Z# _$ d8 `! c9 g: @( t4 y, \& v* d- E
% o; ~6 F! C6 n0 g
————————————————
# o" S0 w- v, I; O: m# t版权声明:本文为CSDN博主「爱做梦的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. \4 s$ u5 w+ @  G
原文链接:https://blog.csdn.net/weixin_43124279/article/details/105904468
% a& d# z* V0 b+ H6 o( U7 Z2 u+ B& ~  b  p" c9 A) G( u' a

  q! M9 Y. ^! O! N

2.png (256.36 KB, 下载次数: 286)

2.png






欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5