数学建模社区-数学中国

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

作者: 杨利霞    时间: 2020-5-4 15:55
标题: 【Java演示】什么是链表?数据结构
6 Z  ^2 r1 y, }/ s; Q. D7 d
【Java演示】什么是链表?数据结构% N- \: n" `( \2 C% B5 d+ q1 x4 E3 p0 L
一、单向链表
/ o& B  |% e+ i$ v& b
) o6 i) s  |" }% Z4 O 1.png
& _# ?) J4 v1 I8 N/ c链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。
9 t8 y+ v" r' S' j- x: |单向 链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。
# W& A: G8 m6 }' r1 S  C) Q链表的第1个节点被称为头节点,最后1个节点被称为尾节点,尾节点的next指针指向空。
$ G& |& @2 U. J1 j5 Z$ o* W* O6 }
( D+ B, v8 k0 J* C& I什么叫随机存储呢?
, Q1 M9 n5 B! ?% T# Q
# q& _; H" Q! }( S# M& L4 m如果说数组在内存中的存储方式是顺序存储,那么链表在内存中的存储方式则是随机存储 。# v! }1 f. I1 |! U/ \( \' p8 w
上一节我们讲解了数组的内存分配方式,数组在内存中占用了连续完整的存储空间。而链表则采用了见缝插针的方式,链表的每一个节点分布在内存的不同位置,依靠next指针关联起来。这样可以灵活有效地利用零散的碎片空间。
7 u' d% T0 O8 T; y- F0 H7 {( ^; i 3.png
5 A& S2 m( @  C- T6 |8 m* q% i$ o2 o6 T; J3 o& @3 X

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

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

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

4.png
$ ~/ b4 V9 l7 ~9 ]- z/ w
! S% ]! x8 h) u  }" h4 H, N5 Q/**
& Z# I* [) \- t" J$ N7 V     * 链表查找元素# d( }! Q( \  D# y
     *& W- T" Y# t6 r0 Q" W
     * @param index 查找的位置
  v0 S+ N  E- T6 X( X. i8 I4 h4 y/ w     * @return index位置的Node对象* z' E  c2 R1 j, o6 ?" F
     */( v& }3 }) U& s4 o
    public Node get(int index) {
: s6 J0 q+ q7 m% D# H        if (index < 0 || index > size) {
/ G, K) Z3 }4 H% E            throw new IndexOutOfBoundsException("超出链表的节点的范围!");
" j/ ^$ A1 ~5 N        }; a- W0 H6 w# i) M
        Node temp = head;
& }5 T8 g1 S& x# ~- g/ P        for (int i = 0; i < index; i++) {
* [6 M0 d+ m% t            temp = temp.next;
7 B' b& g: _+ g4 ?5 r+ _1 Z        }  F- W$ S9 S, q
        return temp;
1 p& c$ l2 ]/ z) z! c    }- @( N/ s1 m* S% ^# F# \! y9 q
& m  C$ d; r7 l3 q

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

2. 更新节点 5.png " c! q4 Y$ D. l; Q: E6 Q, M

, _9 L% P0 u# O' O如果不考虑查找节点的过程,链表的更新过程会像数组那样简单,直接把旧数据替换成新数据即可。' G# O! l' h  r! }8 W
如果不考虑查找元素的过程,只考虑纯粹的更新节点操作,时间复杂度是O(1)+ g0 J& [% s+ T6 f
/**; a0 P) n; k% B$ `( U4 J
     * 更新节点 将列表中指定位置的节点的data替换为指定的data。
$ r+ E  d9 m1 I2 ^& I8 Q& o1 g     *
4 U: z# x6 z- p     * @param index 需要更新的节点的位置
9 v. ~6 K6 C+ M* @& I     * @param data  新data' u& M% O5 r$ L* }( i
     * @return 旧data, g4 v7 Z" R) p3 u
     */
$ }) g/ M4 \8 o& m    public int set(int index, int data) {8 n  x3 L/ k: ^4 h/ w. l& K" x: S  Y
        Node x = get(index);  \! I$ ~: |" f! b6 @4 y6 V
        int oldVal = x.data;
; \7 t! R& ]/ C! `. M# g* Y% n% _        x.data = data;
( J3 r1 b! R# I6 ^% J: q/ R        return oldVal;% |" ~4 g; `9 D" p) s
    }( s8 F0 U& H& {7 A1 t$ s, S
3 o" q8 y1 Z8 |+ i1 R, E
3. 插入节点

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

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

3.1. 尾部插入

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

: ]1 J$ c) F  P' K* B; B3 I* d' D8 N" M
6.png 9 k6 R3 y4 T' G. A& L" w7 [
3.2. 头部插入

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

7.png ) }) ?! p% l) E7 r$ Y( [4 s
+ A$ h  q6 O" b7 _4 u
3.3. 中间插入

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

8.png 5 R$ P/ _# G8 S3 p
- T6 B9 d) G: R: a8 r9 X6 U
三钟情况的代码合到一起, J7 d9 \+ o) Y6 _) I1 m! M& r
" k2 Z5 ?* B8 ]4 I  t3 z% V' G
/**
/ l: W; Y4 f! A8 @7 `9 V     * 链表插入元素
# C& Y: c! ~- ?9 v# h! `5 I7 r     *7 r* H7 e2 ^1 t3 W9 W" d
     * @param index 插入位置
3 o) X7 R: x( F* ^9 D) ]+ p     * @param data  插入元素 被插入的链表节点的数据
+ b' M  e( a9 K  A3 E' Q     */" D* {  k, Y& {, P: f' k- @
    public void insert(int index, int data) {( }. j+ m$ _# B' W' ], J
        if (index < 0 || index > size) {- c. r2 q( p* m4 }
            throw new IndexOutOfBoundsException("超出链表节点范围!");8 E2 z% B. ]' w- `$ V9 G; c$ Z
        }
& Z; P: h. i( W# ^+ X        Node insertedNode = new Node(data);# K7 [# B2 F4 u- i
        if (size == 0) {
, {. ~/ c& r( F, |$ B            //空链表- @) |! \) R1 V, P
            head = insertedNode;
5 c2 R9 }  @" [8 m            last = insertedNode;
! D% W* V( C- V* L% d7 v4 |        } else if (index == 0) {9 `  p& h8 b  ]
            //插入头部
$ c4 a7 }# @8 E& l/ [            insertedNode.next = head;# a% e7 y) T/ T3 j& N. U5 k, f  p  m
            head = insertedNode;
5 h/ Q0 A* q0 ?6 z  i+ A  b        } else if (size == index) {, h0 G( u: t. t/ Q; V, E) G1 N
            //插入尾部5 T8 ~/ p& O, n$ P! V
            last.next = insertedNode;
4 _3 g0 T/ ~  c, ~1 N9 }; f" f            last = insertedNode;
: Z7 c" o' s( Z1 O        } else {
: |  a9 J, p# p! S            //插入中间" \) K" e9 N( j5 O1 A5 T
            Node prvNode = get(index - 1);
5 r' q) X6 f, U, p3 H8 N            insertedNode.next = prvNode.next;+ C0 `) Y/ Y! n0 O7 S
            prvNode.next = insertedNode;0 S: _) `3 x, m/ u- @+ N; \% ~
        }
( q2 j6 T: j" y6 s/ ~        size++;; O! P2 V7 ]% @# n
    }+ V0 {; v6 M2 q5 K3 D7 U
7 k' `8 t1 f; ~: ~  w
/**
/ U7 X5 ?2 Z* }: x2 s" p     * 链表插入元素
7 }0 \, V8 a5 E* \, k. o# }     *
! e! E2 d& K7 N3 u0 S     * @param index 插入位置7 O) z9 W' t3 t3 e- `% \3 {2 ^
     * @param data  插入元素 被插入的链表节点的数据, t& D6 _3 c- f& c
     */6 [6 J% i, _( I. ^- u7 z
    public void insert(int index, int data) {
0 z$ A5 W! k6 G+ x# ^* j        if (index < 0 || index > size) {7 A: q3 _2 c5 z5 l" U$ R5 J
            throw new IndexOutOfBoundsException("超出链表节点范围!");. [/ O' J- n9 T6 |' Z
        }1 s1 z7 u, N+ U4 d+ ^
        Node insertedNode = new Node(data);; `$ f, B1 y( g  X1 B" H
        if (size == 0) {
+ h4 m! G0 ?3 x" J9 {* T# D' p            //空链表
" r4 \5 u% |! u3 ^            head = insertedNode;+ u6 ^  g: Y2 V  @; g) z
            last = insertedNode;' S* Y9 I* U1 o5 B# |: s
        } else if (index == 0) {
; }" z4 D$ n! E* r3 l            //插入头部2 L. C6 ~, ^3 a
            insertedNode.next = head;: u0 S+ E) H* ^+ X" n; v8 Z! l
            head = insertedNode;
( `7 y% }: P8 [3 m        } else if (size == index) {
& g0 l6 ^' X# W" w* O+ W2 P            //插入尾部
1 |  k: V! b& P+ m' {$ U            last.next = insertedNode;
. w3 F2 ^8 e" l0 Z: F9 W5 m+ V& t            last = insertedNode;
5 g$ v0 c: d& {) D7 T' q" ]        } else {
; U) c+ D5 E$ ?4 E* }            //插入中间
8 U" |) P) G: U6 J6 v4 |" {3 S            Node prvNode = get(index - 1);4 @( o! ^  u7 w! ^
            insertedNode.next = prvNode.next;
( Z! v9 Y% l: I3 I            prvNode.next = insertedNode;' W2 g. K% i; Q. ]/ |2 {1 N
        }
. n5 R1 r( o/ n! U        size++;" ?  ?6 o0 m  `; f1 k7 P# b# S5 w: I
    }
1 r6 `) t5 K: I0 x) c5 w4. 删除元素

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

4.1. 尾部删除

尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即
. k$ O! i7 B, k3 E8 e: Q可。

9.png 7 u1 _% h& g: o6 p' k6 M

# B. ^* |; ^! T* Y4.1. 头部删除

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

10.png
3 L. `1 U* L3 a$ E& K8 s
7 f- K- B' @& a- X4 I4.1. 中间删除

中间删除,同样很简单,把要删除节点的前置节点的next指针,指向要
1 j3 ~7 }2 P; s) ?; S' `( {% C删除元素的下一个节点即可。

11.png
( g9 q% u- t0 R( F, D% \2 O7 C/ D6 ~! F5 f6 e! j

" h" S" Q9 l. p; O- J0 o这里需要注意的是,许多高级语言,如Java,拥有自动化的垃圾回收机制,所以我们不用刻意去释放被删除的节点,只要没有外部引用指向它们,被删除的节点会被自动回收。
8 ]% e+ v, T9 _2 k( v. E如果不考虑插入、删除操作之前查找元素的过程,只考虑纯粹的插入和删除操作,时间复杂度都是O(1)
* m0 V/ h/ [5 `& H) T9 v/ a5 m/**6 i; Q' u0 s# {) h  G( R
     * 链表删除元素$ a  B! t  f) r9 i
     *1 `5 q& c7 k4 V9 ~! g
     * @param index 删除的位置# }3 L6 Q4 u  N4 ?+ q) H$ [
     * @return 被删除的节点
- ]7 C. P% W; }+ s( U8 t$ q  f     */; m' R! F$ K% r9 o" ]/ s) j
    public Node remove(int index) {( D% N9 y" H8 U' X
        if (index < 0 || index > size) {
- x0 ~4 O) y3 U            throw new IndexOutOfBoundsException("超出链表节点范围");
. J4 s3 J# b8 F8 F3 Z5 k        }
& f& J# h$ [" k$ l) p& {% g/ t        Node removeNode;
/ {7 X5 F- [) t/ \4 h, A( ~        if (index == 0) {" k( C( Y* V+ z/ ]* A! y7 q* E
            if (size == 0) {
, @0 N8 i/ e- o& i- i                throw new NullPointerException("当前链表为空,不可以进行删除操作");: t4 R/ U% h) i
            }: U. t! m# N/ k5 ^0 o& A
            //删除头节点
' b2 V1 p8 R6 ^2 }2 s            removeNode = head;
3 ]6 B! [- a' Y, o9 N" h  \            head = head.next;1 o2 r& _1 K% l0 @7 Z
        } else if (index == size - 1) {
' P2 d9 ~% c, e0 p            //删除尾节点( n1 `( C1 @# c5 I+ K
            Node preNode = get(index - 1);. R- A* P: T: ^3 E
            removeNode = preNode.next;# A0 b3 T$ j! K: W: s2 W0 k0 O
            preNode.next = null;
# P) S8 Y6 c" q& B' A# b            last = preNode;
# r+ F$ ^/ y# F4 n        } else {' T) i3 j6 m% v$ M) j
            //删除中间节点; a1 Q% X2 W3 P6 @: X
            Node prevNode = get(index - 1);
' S, ]4 f* h0 ^3 O) h% a            removeNode = prevNode.next;
1 M% H# l9 i- S* _2 i% a$ h            prevNode.next = prevNode.next.next;# T' D0 T5 h" |" N
        }
2 F* Z9 y% S( o* P        size--;# l3 ?4 o; c& A! Z8 F% w
        return removeNode;+ I1 |3 j+ i" v* W9 {
    }7 ~% t6 n: x3 ^+ U
Java实现链表的完整代码package chapter2.part2;! I% K, w- f0 V

6 H+ ]* T/ ]% S" \9 E2 h0 m/ a/**8 E: u, l, x8 c9 m" |$ x9 J
* Created by IntelliJ IDEA.% @5 A3 b9 E( U" G  N4 ]9 I
*/ ^. E$ ~8 z8 t) @4 l5 n( O/ y. H
* @Author: 张志浩  Zhang Zhihao
/ T" y; z2 N' w * @Email: 3382885270@qq.com/ ^! s2 h& O$ f: n. A) T
* @Date: 2020/5/3
* P. M: ?$ b: t: b6 @% Y3 |8 p * @Time: 13:39
+ O$ e0 M: [& ?+ z * @Version: 1.0
! x) g: b# R  [/ P) `, T/ \, u" U */
" f0 c: `/ H4 t( T# H1 M8 jpublic class MyLinkedList2 {2 R3 S$ I0 r& o& ^
    private Node head; //头节点& j- X: g7 t/ Z' f# G- {: b$ b
    private Node last; //尾节点& @* B& t1 g$ x! q* }: g. X
    private int size; //链表实际长度* M/ s/ A3 ]4 [9 u

7 s2 R7 A# W* @; o5 k$ s    public static void main(String[] args) {
' @* U2 y: e4 Q        MyLinkedList2 myLinkedList = new MyLinkedList2();: I' v$ J" j" D7 @7 @
//        myLinkedList.remove(0); // java.lang.NullPointerException: 当前链表为空,不可以进行删除操作4 W! b; W$ V( W5 S# l  \) q, A
//        myLinkedList.remove(3); // java.lang.IndexOutOfBoundsException: 超出链表节点范围/ S8 m3 P+ Q8 O$ {0 l$ j/ W4 @
        myLinkedList.insert(0, 3);  Z; ^5 H2 J, A
        myLinkedList.insert(1, 7);+ M: p! v& Y; Q3 i
        myLinkedList.insert(2, 9);
4 f! a: |1 b2 Z2 M        myLinkedList.insert(3, 5);
; q  Y( k, h- ~) |8 l4 P        myLinkedList.insert(1, 6);
6 f- K; l2 j' i: J$ I. \        myLinkedList.remove(0);
$ @- Q3 |0 z% m3 C3 h        myLinkedList.set(0, 23);
- s  ~: ?3 j1 }, F6 Y9 S0 M        myLinkedList.output();" B+ j% w4 N# x$ s1 g3 p; j
    }
1 U- g1 P$ L" \( U1 x4 h8 g! [
; X5 V/ b: G( r$ h+ a; G    /**
5 A; Z' _. Q, v     * 链表插入元素: C# _8 Y6 p  P! T7 O
     *4 ~+ Q+ h! j6 s2 i) ]& h
     * @param index 插入位置
( ]  x4 i& F, s2 ^7 s. F7 Z' o     * @param data  插入元素 被插入的链表节点的数据
6 _$ }; ]7 ^" j     */+ ]( A0 A3 v3 I- \
    public void insert(int index, int data) {5 v! C( x  B4 `5 P5 j. H1 x# C; k
        if (index < 0 || index > size) {# X" `" N1 `- N+ }
            throw new IndexOutOfBoundsException("超出链表节点范围!");& r( {5 J& ^5 o3 u
        }
% y! V. L  i, J! }8 k        Node insertedNode = new Node(data);
% i! V4 B( d. c! Q" l5 E, M        if (size == 0) {" ~' x! ~5 G6 W
            //空链表$ j+ C6 {9 k+ n$ d2 B  B
            head = insertedNode;. c' V4 }" l3 o/ b$ T
            last = insertedNode;
" X( J. c3 D) |# F7 u* Z        } else if (index == 0) {* ^$ b7 Y# `: B! @( t
            //插入头部8 C: k& R) F8 ]# K# B2 K
            insertedNode.next = head;
4 V' X, l7 M. b' e            head = insertedNode;7 T5 L5 U+ E# N. _; t0 L
        } else if (size == index) {
! N# t7 \+ o0 r4 F( j* e  r            //插入尾部
# M) l$ n% H: q3 t7 r            last.next = insertedNode;: B4 A3 r9 t: K  E
            last = insertedNode;
% z, ^. N/ ]& u- I$ ]5 d0 _        } else {& H/ |6 i" A" f6 {( f
            //插入中间% f" P0 Q1 a' j; K  @, |
            Node prvNode = get(index - 1);
0 x' ~, O( y  d  I- Z8 H            insertedNode.next = prvNode.next;  D% G# A6 n/ a* ^
            prvNode.next = insertedNode;
' @- C8 _! m! O- Y: M  L        }8 n7 u" j) Y( r* z" D; c% G! Z% }8 E
        size++;+ q- l7 R9 g  @# M; ~
    }- F2 W. T  J5 g' |

% u2 ^& O4 }/ |- a2 [9 v" a    /**. {( l2 e8 |8 p- c- x
     * 链表删除元素
9 z& h) c% a, \+ u     *0 O3 o; \2 S  `
     * @param index 删除的位置; [& m- A# C; p( G9 }8 v
     * @return 被删除的节点
5 @/ F# E6 C+ z6 @" I     */5 M* Q! h# d( n
    public Node remove(int index) {% S) k8 C1 b* _8 r  t* u+ }' x
        if (index < 0 || index > size) {
; u! K6 N, \0 W- b# X  \            throw new IndexOutOfBoundsException("超出链表节点范围");
* ]* P! X5 `3 q2 T. B        }0 k  _5 N$ h5 ]$ F+ I/ T7 j
        Node removeNode;
# Y1 O9 k6 ?' P' c: j7 I        if (index == 0) {
. y5 c0 ~6 W6 l) l1 u            if (size == 0) {
& b4 }7 C# [7 H- a1 I7 ^; v  e                throw new NullPointerException("当前链表为空,不可以进行删除操作");" j% _" e* s7 s% S. W6 Z# b* w
            }6 q0 h' p* |5 g& a& H9 u
            //删除头节点
7 m1 c! b' R+ C7 R/ [            removeNode = head;
7 T& g; G0 ~* j' ^3 a: P            head = head.next;
- T* H* c5 \, q8 Z  _4 ~        } else if (index == size - 1) {4 [0 f5 T& `, F9 |
            //删除尾节点
4 z# X0 e' F, Y! r            Node preNode = get(index - 1);
7 q7 r$ e  [! d/ M, o! W            removeNode = preNode.next;
9 T6 m/ j& s+ p7 W* v( q; q( E            preNode.next = null;
8 f' E' R! y! X4 s* P( P3 Y            last = preNode;. b# m+ K! i& R) J- J+ |( |% |
        } else {. y, A% T2 l7 G, Q/ h* v2 A
            //删除中间节点
" d4 W. S$ [- r- D            Node prevNode = get(index - 1);
* ^$ B  u" D" W            removeNode = prevNode.next;
! Q( e& Z: _- a; l8 N0 r9 A            prevNode.next = prevNode.next.next;9 w' S3 N, {: L: R
        }
% W4 N3 X8 |: T1 K+ d6 Z, i        size--;: v; M9 S! K0 q7 Z; x, s% Y
        return removeNode;) I/ m/ o6 F8 x3 ^9 a
    }1 D& F, A1 C* g$ Y0 P

- u, p% Q, u% w    /**
8 {! ]+ |# Q- Z& s/ |, U     * 更新节点 将列表中指定位置的节点的data替换为指定的data。
: D: ?' s2 j; ]; [' J9 U) j1 C/ c     *
. ?9 x+ l; P6 e6 e; B     * @param index 需要更新的节点的位置" [" c; M0 f5 p5 C3 t3 w4 d, S
     * @param data  新data
* L, e8 V. Z" s     * @return 旧data
* ~- d! ^1 ]- ]0 o% {     */: r0 O- P, N& y5 V+ b% U  P
    public int set(int index, int data) {
8 Y4 \' n% }9 r) B        Node x = get(index);2 h$ [6 a6 l, n- i
        int oldVal = x.data;
2 i# d3 U% E; s2 P9 m2 _        x.data = data;# {8 |( O; N( \# b2 a0 g
        return oldVal;- y, A' d' p2 N
    }) S3 B$ g5 g6 V% @+ A% R

  @6 P1 Y! |2 ^' Q, U    /**
- G4 J0 b5 Z1 J: i7 K+ L     * 链表查找元素
6 I; e2 Z" D+ ]" u  L1 T& c7 F     *
: l, p% \/ j3 L  H$ W9 }0 s     * @param index 查找的位置
& Y" p- [+ `- \) c" M3 J     * @return index位置的Node对象
) C  {2 U5 q( I8 z! X# `6 f1 _     */8 z+ q! X; q6 h8 t, D
    public Node get(int index) {* @4 v  {- L$ n. l! k2 ?* O# w
        if (index < 0 || index > size) {
- N" T$ u/ X: J$ P6 H            throw new IndexOutOfBoundsException("超出链表的节点的范围!");% t/ }; Z. u1 G7 r" O+ X
        }) s0 {4 l; d% D7 v
        Node temp = head;2 _, }8 g1 V7 }+ Z1 j
        for (int i = 0; i < index; i++) {
" g& K: g$ R; u* O            temp = temp.next;
% [! w2 G5 G* J# ]( Z0 w        }7 |1 V% p5 l: I( T( ^6 \' @
        return temp;0 _9 y4 y" K! n1 F
    }
1 F( m5 L/ u% X& G9 w( X/ U0 D2 }: _
. f- ]; @) @# R% J' ]    /**
; |( p9 w1 `" v0 ?     * 输出链表& q  o* h* V/ T  w; v
     */0 t2 c  R, ]) \5 \$ T
    public void output() {8 m  b! u, I. v1 h& c* h) i) c
        Node temp = head;& j. I# R' `  u) ?+ t
        while (temp != null) {7 o! _- E+ f5 x/ Y9 X" v2 B
            System.out.print(temp.data + " ");
: X, y* o7 ]. ~$ e, M4 d            temp = temp.next;
1 L7 }# G% j0 T, D  b  \        }
: d1 t5 _/ t& e    }7 G9 i9 t2 v( Y/ C

  c  V" X0 e& P0 B8 a/ z0 S/ W    /**
0 g4 t( E2 L; i( m6 R     * 链表节点
% P9 y# M& Z" W) }6 H2 k     */. Z& a1 F! z3 W, F
    class Node {
! N) ^0 b4 Q1 r- F7 \        int data;, s0 d) X# H; r9 q4 a, K0 U
        Node next;
6 a3 `* A4 Y9 \+ w5 ?- S5 P+ t! P( \. }, E
        Node(int data) {
" I1 F5 S1 @& N) ^# D: |0 `) Z            this.data = data;* G+ @6 l7 f6 r0 T) j
        }$ W, p& f, S+ s( o4 m
    }: A8 D% f+ I4 E6 n3 {$ k/ W/ |! G
}
* h: C8 w* L& k4 a7 [6 K0 K% E7 V2 j2 q0 f( J. B

/ A% I" S$ F5 G0 |二、双向链表 12.png - z# n' L# K6 I* i
双向链表比单向链表稍微复杂一些,它的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev 指针。
, E$ Z5 R) T! R1 H0 K) i
& @& _, P. ?& |# v9 ]
. f4 Y+ t% i7 H4 N" `0 M: e" m" h" B; L' `

8 R( C; u+ q/ v: m% v————————————————5 e( F( D8 ?; [6 i* O0 ~: j
版权声明:本文为CSDN博主「爱做梦的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  h1 v) `* ?$ N8 l) q) Q9 {原文链接:https://blog.csdn.net/weixin_43124279/article/details/105904468
) P' D6 o+ \3 ~0 P1 a) V! h7 Z+ f2 s+ X2 N1 P: ]% E; Q, h
- {# ]# T" @. ?; r

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

2.png






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