数学建模社区-数学中国

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

作者: 杨利霞    时间: 2020-5-4 15:55
标题: 【Java演示】什么是链表?数据结构
2 Z8 P9 o1 h1 k* p2 u' r
【Java演示】什么是链表?数据结构" N* S: D+ Y# L
一、单向链表1 N7 t/ j+ d: b2 Y1 l* M  M
" F2 \% m$ k1 w- f( R0 ?
1.png
0 z. d9 n$ `1 s5 y; s2 I, z. Z链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。
) s+ Q$ e/ J  j+ \+ Z, n1 o! }8 `单向 链表的每一个节点又包含两部分,一部分是存放数据的变量data,另一部分是指向下一个节点的指针next。
" O5 J$ d6 a0 r8 y1 w链表的第1个节点被称为头节点,最后1个节点被称为尾节点,尾节点的next指针指向空。
8 P3 t3 q" }6 G) s; y/ @* X! ~+ B# k3 _! |7 g+ V+ @- Z
什么叫随机存储呢?0 m) \  n) s8 ]$ I: [

3 W. m8 J7 Y! ]6 l% F如果说数组在内存中的存储方式是顺序存储,那么链表在内存中的存储方式则是随机存储 。5 \- L% e3 r6 w; z- e( y3 n
上一节我们讲解了数组的内存分配方式,数组在内存中占用了连续完整的存储空间。而链表则采用了见缝插针的方式,链表的每一个节点分布在内存的不同位置,依靠next指针关联起来。这样可以灵活有效地利用零散的碎片空间。) h$ \9 o' D4 T; {/ g! j
3.png ! |. W# N5 D. l1 s  k. l

, K! F# S8 Z% P

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

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

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

4.png / I+ i- ]! W/ c5 a. `. X
; r& q& u: S; \2 _
/**
) @5 W3 x+ y( U) J     * 链表查找元素
% S  `2 b7 m8 ~: i+ ^& I     *
1 B, T/ N% Y8 f1 U     * @param index 查找的位置3 }) B7 B6 a8 ?& }1 i' y. I# l4 Q/ _
     * @return index位置的Node对象8 x9 ~  K1 b) o6 A+ l/ k* ?4 r
     */7 A7 {  d+ h5 ]
    public Node get(int index) {0 P- v3 ^( v( d9 i; o
        if (index < 0 || index > size) {
1 a, W$ a3 h6 h4 Q, C0 X            throw new IndexOutOfBoundsException("超出链表的节点的范围!");9 F6 M/ B7 x' C- w+ J
        }
( d4 M3 e2 H4 _- U) {9 ?        Node temp = head;. M  }7 \/ }1 M
        for (int i = 0; i < index; i++) {( g  o' \0 S& b$ V: k: b& p
            temp = temp.next;
4 F% E' I' v& o# B. k% o        }
& y3 i, T0 O4 e3 r3 L        return temp;
5 ^5 o- P1 D) W0 u    }
1 N. h( D0 }( `$ t% S6 z+ N: z
4 ]# R' @) h% e$ J* r

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

2. 更新节点 5.png / [$ e  F5 o. w% J4 t: I% c, ?& b

9 ?9 A! t& i8 g" [如果不考虑查找节点的过程,链表的更新过程会像数组那样简单,直接把旧数据替换成新数据即可。" d% t' h9 B8 P5 i
如果不考虑查找元素的过程,只考虑纯粹的更新节点操作,时间复杂度是O(1)
3 t; v* n# \. r  q: V* I( b/**
9 q9 c! w1 N  l2 r% B     * 更新节点 将列表中指定位置的节点的data替换为指定的data。1 T& a! R  R. c$ y! t0 F0 `; X
     *
. M0 k. l6 A6 P1 u7 `) L     * @param index 需要更新的节点的位置8 a# H4 S- z6 v% K, _1 K
     * @param data  新data0 v- T. C+ i/ o% X
     * @return 旧data# E" }% f$ v! }& Y
     */
" y1 a0 J& T* h    public int set(int index, int data) {& G6 Q* G$ n+ S* F0 Y  @
        Node x = get(index);/ v- A6 [" t' a# a# e* b+ z' N9 h  Z
        int oldVal = x.data;" ^) D# X0 E* h- p# g% }; |
        x.data = data;. X! N8 b! b# _, r8 O
        return oldVal;6 i" m! ^# w5 m9 R2 V
    }( Q- P6 r- Q1 S- e
3 @# n1 \% `8 R6 J, H
3. 插入节点

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

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

3.1. 尾部插入

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

- ?$ L' H0 o$ J8 S+ R
6.png . z8 T1 |/ |  g  D
3.2. 头部插入

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

7.png
7 v* w% f/ {/ Y4 @. ^8 A! K. x1 T1 r5 E* H% L' Y7 p, m
3.3. 中间插入

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

8.png
* w; I/ ~, J% q: H! v$ t4 }6 _0 @9 v1 i9 p/ [
三钟情况的代码合到一起+ u, N( k: t4 C& S% E
7 a6 d  `+ w: u
/**) I( @; r" J; t4 Y; p( q: ?) b* U
     * 链表插入元素
" }$ @! ^5 v0 h: I+ Y5 y( V     *
( @2 l: A4 T, P# a  b: C     * @param index 插入位置
. j" v7 G- h# f# u     * @param data  插入元素 被插入的链表节点的数据
/ X; V; W% C8 B     */
- b" {7 ~* y% j7 [* J1 d    public void insert(int index, int data) {
- K, H3 O' t/ e& ^0 H2 d1 }5 H2 \        if (index < 0 || index > size) {
. @3 f7 q9 P6 d            throw new IndexOutOfBoundsException("超出链表节点范围!");6 V0 o7 T# c/ z2 q# V
        }+ q  n1 {2 @1 Q" N: W
        Node insertedNode = new Node(data);
7 v6 Z2 z% `5 l! F6 C4 F0 F: U        if (size == 0) {
" e3 R, m: v( Y            //空链表
- i4 b" o4 |! {; s/ F- [9 w6 d4 r2 ?            head = insertedNode;
4 V. X! K, G" G* D; d            last = insertedNode;) X# V* u6 p4 f+ s8 y* U0 W: P
        } else if (index == 0) {6 s9 l! Q: |# I" p8 m# O& @
            //插入头部
6 t* T2 Z0 q8 ~- `/ h* n            insertedNode.next = head;
3 a' [* |/ g( A  G9 h            head = insertedNode;
: g: a8 ~" x5 g& G5 D4 ~) }        } else if (size == index) {+ q$ z% G, m  ^- F" z
            //插入尾部8 Q7 G% h/ H& V/ H) z" J
            last.next = insertedNode;' I5 r% \# o" o% [$ Z" S
            last = insertedNode;
0 B# P/ C) B4 }, f        } else {. S- i  B2 ^) R; {+ T2 L" r
            //插入中间
2 _# t7 n/ P3 }2 i, }            Node prvNode = get(index - 1);8 ^: P5 X) v3 n: {5 L8 S& }
            insertedNode.next = prvNode.next;6 d4 h8 q, `0 u& [$ K
            prvNode.next = insertedNode;
) V  }2 T, n# Z1 {( J! d        }
/ d8 Y/ a$ s# q* O, m" z4 r0 R        size++;
* @( U7 z! g4 _    }" h6 K! h6 z  B0 g% n

. W& B$ E# K& l4 I& g; I/**
% [/ Z4 {; A$ S# z* ~9 j2 s& F     * 链表插入元素
2 H  G6 T+ U4 t0 p     *
8 ~+ U2 t" Y5 x2 P2 b7 `  k     * @param index 插入位置0 W6 Z9 N; y5 I. h' A
     * @param data  插入元素 被插入的链表节点的数据
9 \* M" ^9 o, _/ r     */
: B9 }0 e: P  c% Z+ h2 ?    public void insert(int index, int data) {
8 C6 x+ u4 S" i        if (index < 0 || index > size) {
/ Q3 H9 B7 }  V: H$ O4 \7 H" q& n            throw new IndexOutOfBoundsException("超出链表节点范围!");
$ U4 Y$ f" y4 ]6 R9 i' P% n# M) W7 F        }
# t! \$ h( @: L* a        Node insertedNode = new Node(data);
  @  z9 g6 |6 @        if (size == 0) {
+ [& H* C7 {; p; U0 f            //空链表
5 l" q! g' |) D2 J& W            head = insertedNode;
3 r! P4 m" I4 F* e7 S            last = insertedNode;$ p1 s  R. o' e2 v6 O, C# O
        } else if (index == 0) {
% G4 I+ B1 b) ]# a            //插入头部
+ f% n! U0 r+ F0 Q  D+ ?* |            insertedNode.next = head;4 x0 J5 |) ~' N! A: ~: T. l% [
            head = insertedNode;
% K  R1 [: l6 R' _        } else if (size == index) {
' \+ m! I# J- j9 w: v' h4 V! _) H            //插入尾部$ C4 C) c8 D/ m, o; S% {
            last.next = insertedNode;1 a/ U8 {; }6 v& J& F$ \0 x6 Q
            last = insertedNode;
7 f+ `* L3 i! G0 S" O  x& u        } else {
* Y6 a) a2 l# [% W            //插入中间/ c# X1 }. L0 P2 D3 x
            Node prvNode = get(index - 1);- k8 {2 l" n8 U/ X4 ?0 v& `+ [- D
            insertedNode.next = prvNode.next;
% w6 ^0 ]' a) E& e+ v( E0 H+ N            prvNode.next = insertedNode;
3 m& w4 ^4 C) K: T7 S. w        }! |/ w2 K1 z3 k
        size++;9 }- w! ^" N8 c- s, I
    }
! B2 T" |/ G- Q4. 删除元素

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

4.1. 尾部删除

尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即5 D" p& H$ i9 l6 B
可。

9.png ' Y1 m% m& b# G( D$ f5 q& p! {1 h

4 F' q  E, d3 M+ }* v4.1. 头部删除

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

10.png " C. K% v  u$ p1 v+ u% B$ M
* G, @. f  Z9 I; T+ [8 b
4.1. 中间删除

中间删除,同样很简单,把要删除节点的前置节点的next指针,指向要
6 T& {3 v& f6 |' M! B/ H删除元素的下一个节点即可。

11.png
$ }! F% w6 p2 ~
  F$ ~! A5 I' Q3 K$ P7 a
3 @4 L  ?1 T! r3 o$ L* O! }这里需要注意的是,许多高级语言,如Java,拥有自动化的垃圾回收机制,所以我们不用刻意去释放被删除的节点,只要没有外部引用指向它们,被删除的节点会被自动回收。
& Y! j! A  ^, g+ s) i+ ?/ w7 W如果不考虑插入、删除操作之前查找元素的过程,只考虑纯粹的插入和删除操作,时间复杂度都是O(1)
2 C! D0 r# O' t1 Y7 s3 g/**& K( l% k( p( m, w; `
     * 链表删除元素% G5 K1 Z% F* l5 m( P
     *
( [/ c$ }/ D, l  u0 W3 U+ H% W     * @param index 删除的位置9 {& g$ X) R* S( E
     * @return 被删除的节点& h4 T1 x7 |) w- E8 y
     */
! i+ a1 x0 ~; X- \    public Node remove(int index) {0 P: i6 T3 K/ l, G1 _
        if (index < 0 || index > size) {
- H; R% D9 D: F- y8 i7 F7 Q0 G            throw new IndexOutOfBoundsException("超出链表节点范围");
5 `4 U+ I0 r6 s# H7 C        }
+ _# B- Y, g5 \! p: x        Node removeNode;
, o' @, Q# p  ~" f7 H& F( y        if (index == 0) {" V7 h1 r. o; e. k5 |1 v! a
            if (size == 0) {% L: j1 x8 V+ l- b2 H
                throw new NullPointerException("当前链表为空,不可以进行删除操作");
/ m7 r7 N' w7 c- p            }
5 o( ~5 w7 h3 g/ H1 g* `            //删除头节点
$ w9 W' \1 A" \' T; J6 n            removeNode = head;4 f1 W8 a* m# m
            head = head.next;
1 G* H. w. V+ Q6 e7 J3 ~0 J        } else if (index == size - 1) {: [5 }7 s/ b  U; {! a/ i6 \
            //删除尾节点
/ \) ^( `4 r8 U. j7 _8 x            Node preNode = get(index - 1);% S! f! r8 Y0 p, S1 U9 V; N3 X& _8 h
            removeNode = preNode.next;
5 l" A& q: ]8 y3 R            preNode.next = null;  z, m4 G% o' O. T0 P# e  o7 E
            last = preNode;$ S/ f) e4 F" G* u4 F
        } else {
; n. g& f) P3 k4 l* R7 m            //删除中间节点
( `4 ~6 s% H" o6 Q: i            Node prevNode = get(index - 1);8 \$ ]* H1 g5 A9 m
            removeNode = prevNode.next;
& \6 E0 A" O# J            prevNode.next = prevNode.next.next;5 ]% r( r2 b7 W* \" T/ N( K2 e
        }
" A/ l' ?8 |( W! \( h( S        size--;
6 x: h$ h' C/ g5 w        return removeNode;
2 X; W- f% C! X4 @. L( w    }
' k) H" u: H, m& {) [2 W* TJava实现链表的完整代码package chapter2.part2;# _  e) M9 Z. t/ j! B
3 C8 ]' S2 h: `5 E
/**; a% ?' i1 E8 c* _0 _* K8 h; T
* Created by IntelliJ IDEA.
8 p. }: ]: m5 ~2 D/ g *1 z" i3 r$ \! n; c1 x5 g
* @Author: 张志浩  Zhang Zhihao. g' ?" i7 g- }) A7 G, O
* @Email: 3382885270@qq.com7 c* }( r  A) u( a3 Z
* @Date: 2020/5/3
5 @. H6 D1 T+ X* ^" w' W( S * @Time: 13:39
5 d% I. L1 e) R6 H * @Version: 1.0- D8 V$ w; M6 h6 G2 A: q
*/" Q/ A4 G2 B0 X
public class MyLinkedList2 {( x  o/ t3 i) C$ T1 p5 C9 t
    private Node head; //头节点
( M& U$ p0 e4 f2 n, ?9 j    private Node last; //尾节点
7 N/ O. G2 x- o1 w6 N    private int size; //链表实际长度' v* w9 X! K" X* u

) Q3 G7 R1 j( u# m: s3 o% [    public static void main(String[] args) {
( i6 q! J, l6 K- m# V( _1 O, H        MyLinkedList2 myLinkedList = new MyLinkedList2();
. G. Y% _) b- p. y//        myLinkedList.remove(0); // java.lang.NullPointerException: 当前链表为空,不可以进行删除操作1 n* B3 K! A3 l' @/ D1 e( v
//        myLinkedList.remove(3); // java.lang.IndexOutOfBoundsException: 超出链表节点范围8 D1 h/ E/ P4 S! i, ?2 {9 ^7 n
        myLinkedList.insert(0, 3);
3 u! }. t, u& s( c# h" g- {7 R6 W# ~        myLinkedList.insert(1, 7);
/ q% v3 D/ D8 V0 m        myLinkedList.insert(2, 9);7 I/ `* [: a" F' S
        myLinkedList.insert(3, 5);
: k; F& \7 ~3 |! f5 \" I+ e        myLinkedList.insert(1, 6);2 b4 o8 l9 o  M# G% l1 X
        myLinkedList.remove(0);9 _& p5 F" W# x
        myLinkedList.set(0, 23);
5 Z# O" J! e: E" `        myLinkedList.output();, K, b# j6 z" `3 J: z
    }
5 k! \( J' j" K. i. T% _, C+ a7 N: H) |! B: Q: o
    /**
' }! e; T9 u- a! W$ y# u7 J7 G     * 链表插入元素3 \$ }2 ~/ E* R1 O# G/ e
     *5 R% z. V0 x; [) r2 h" A
     * @param index 插入位置  T8 b7 E# B1 l
     * @param data  插入元素 被插入的链表节点的数据$ Z+ ^) U' G5 t8 s
     */
. X; C) R# Q; o9 `% [8 X7 m    public void insert(int index, int data) {
# B! ]9 W$ Z4 Z/ L+ }0 G' q6 q* A        if (index < 0 || index > size) {
" \4 t. m2 z: q& m0 C* _. h            throw new IndexOutOfBoundsException("超出链表节点范围!");" \5 I3 y9 H4 f6 x; A
        }( e. }1 X* ?- S( N0 L" n
        Node insertedNode = new Node(data);- i$ N( l0 A2 y) U3 J& D5 e
        if (size == 0) {( j* Z2 ]( T$ E# M/ u& O) }% W
            //空链表' @5 Y- ^; F6 K, B5 X) S
            head = insertedNode;: R- O7 M& c7 F( ?! `
            last = insertedNode;2 n' j: ?/ n. S  V6 p( G7 g
        } else if (index == 0) {
/ u+ J2 z7 G! e6 k! R            //插入头部
+ i4 j) D7 O6 Q  D6 E4 U            insertedNode.next = head;
/ ]5 S2 E7 o. t7 U: k9 {2 e            head = insertedNode;
# K1 O: m8 I( W& k* O- P        } else if (size == index) {
* b7 g8 w/ {1 R- [/ N4 ^  t            //插入尾部7 V( g; W  r- j+ t0 S
            last.next = insertedNode;
. v9 Y$ t+ w2 b- j, B: z) U2 `* k- v; H            last = insertedNode;
' p, d$ K3 q- T: b        } else {
' a# L9 u* R; I3 r0 O+ b: D            //插入中间- P9 r" y! f. f! l  i. [+ U% \
            Node prvNode = get(index - 1);
* N2 y& Y' R7 ]2 I5 p            insertedNode.next = prvNode.next;
- f7 d6 a. m& U+ A9 @9 D            prvNode.next = insertedNode;
* l$ P/ R, ~2 Y& {. Q. i0 R        }8 y0 }$ p; @3 s' Y1 q  e) E
        size++;$ y6 |! D! r  R6 `7 T( e0 K
    }3 y8 D  r9 {# r3 Z( u& K
) I% C% X8 k& x
    /**1 c) ]* d. s/ b5 Q
     * 链表删除元素
8 ]6 ?* F: I0 P% G$ W2 X     *. m) \" k$ H: c7 V- R5 w/ p* O
     * @param index 删除的位置
0 V* P. G7 M; p; L0 L+ ?, f" V     * @return 被删除的节点
' ]& w" {( ]6 |5 J     */1 A2 O+ V! k9 l2 _
    public Node remove(int index) {& B6 _1 ~% v( P6 ~( u
        if (index < 0 || index > size) {
  m; P4 M  U6 [# f6 L            throw new IndexOutOfBoundsException("超出链表节点范围");
6 w* D, F# [7 r  C6 N: f        }
" }# {8 O, K, p4 B0 W        Node removeNode;: Q* r  e  }, X! S
        if (index == 0) {
+ I/ ?! k: Z, C( K- _- W& ?/ P( `8 j            if (size == 0) {/ M$ r* j  ]0 K* Z* z
                throw new NullPointerException("当前链表为空,不可以进行删除操作");# b7 n1 S% f9 @
            }2 ?, a3 Q. d0 v( h7 B. ?" _4 _
            //删除头节点
. h" g5 G7 C* ^, c# u            removeNode = head;
* P$ f! a  J5 q/ I            head = head.next;
; K3 Q7 p  K" z- `' e1 `        } else if (index == size - 1) {
$ S* ]& e# a; P$ f( G  u2 t- F( r            //删除尾节点
  O4 }, l8 \# e7 X* h            Node preNode = get(index - 1);& T* _0 P3 k" e) i! b0 h+ {6 f
            removeNode = preNode.next;
4 K6 i& z( q& I: i% _1 m            preNode.next = null;
1 d3 D! f% d8 ?; p; A( i            last = preNode;3 R3 w6 L& ^# j$ ^; {: z) Y
        } else {& ^) {: [3 U7 b: B4 K( N. [4 o: s
            //删除中间节点) j4 q$ K: l6 p  J- A4 |( r3 V2 z1 ~
            Node prevNode = get(index - 1);
7 ~( H' }7 o6 x$ F            removeNode = prevNode.next;, A& ?- Z5 b; m5 S+ H, R: L, y5 v
            prevNode.next = prevNode.next.next;
$ f/ Y7 O% C$ U5 \/ u        }* k+ ?6 }& T" E' @) o: e2 `8 O
        size--;
  X) W8 K+ I4 l" H        return removeNode;
7 t% P$ K9 C$ r' t' g5 r- U    }+ q3 U+ Q' ^( H. p$ c' S" k
: L7 ^: Z  v# J+ c' D0 }3 h. ^* ^
    /**+ g3 c' h0 R, z  ~- V
     * 更新节点 将列表中指定位置的节点的data替换为指定的data。
8 c* |3 k9 T( P! ]; }     *: O9 O) c9 T( o# Q  c
     * @param index 需要更新的节点的位置
( m7 j. F0 E/ T2 Z) b; o% _$ D1 |2 D$ U     * @param data  新data0 x# E, W6 B* \( x  \
     * @return 旧data8 p, r* U& O5 u1 n; Q' ?
     */
7 d. X- ~2 X, U    public int set(int index, int data) {
( |# A/ D' a5 d' Q        Node x = get(index);" L* C" v% @4 @
        int oldVal = x.data;4 p$ U0 B( R- V: |0 J3 f! H
        x.data = data;
. m7 c. s; s, S3 p        return oldVal;" `7 a+ H) d* x2 w: y9 b
    }
( I  e: w* p! h0 C, X# @$ [* v: Q5 b1 X: X
    /**
2 L+ P0 v0 C% i# N/ p# A" M     * 链表查找元素6 p7 M) d2 c0 s5 V, ~# m
     *
5 i- G* R9 x( q+ g+ M3 {     * @param index 查找的位置2 y+ _+ h0 j7 d% _/ R  U
     * @return index位置的Node对象
9 f8 D+ t( i- Q7 I0 |     */4 i" h8 y' i! F( g# C. j3 N
    public Node get(int index) {
' \6 i( a, l4 D$ V- _$ s- ]        if (index < 0 || index > size) {* a8 [% u& Q8 J) U$ Z0 r- |2 e
            throw new IndexOutOfBoundsException("超出链表的节点的范围!");  Z# |% A) u7 ^$ [. t
        }
" Z) Z& C( Z8 S8 e        Node temp = head;* F" v2 u# R! N& P
        for (int i = 0; i < index; i++) {
! T0 G6 C8 s3 K+ q            temp = temp.next;
: p$ @- p4 {2 T' v        }
5 ~5 P' |/ o0 u* J! L) L        return temp;
0 h' j% m( Z0 P3 M  E3 U0 H. T2 d    }
0 z6 `1 D+ e# V+ M
% R4 g( D0 x" i) V" q# I1 J  [    /**) `) Q, Q: M- i& M. G5 [
     * 输出链表! I* h0 p/ L1 D/ n  A6 \
     */
# f; @+ _2 N+ H, z" Q+ D! ^, S    public void output() {: R8 _, X1 m3 B: d
        Node temp = head;
9 R1 H# s; w0 b        while (temp != null) {5 I% \# d% u7 y8 |
            System.out.print(temp.data + " ");
, R" D, h# y5 a4 C( f! a$ j            temp = temp.next;9 B4 V+ p- k( S: l5 ^
        }9 a& ]5 r' N9 c+ E8 O
    }
+ U2 F+ }5 Z% y1 F1 J" @: J( S0 c0 s
6 N" c7 j9 w; {& w" X    /**
. z9 W. K; u2 @9 ^& C8 p     * 链表节点
  s6 A/ U. h4 v7 d5 N' b1 F     */( P2 o3 c! U% p1 W) y
    class Node {; H/ A. P/ T/ V- {
        int data;2 p8 @- G% S8 @# {! p& O) o- j
        Node next;
, ^/ v) D. v' |7 y) E# K' R4 N, k5 x( e( r! G
        Node(int data) {
1 O  c  n/ c: L, Q" F; a/ W% J6 V            this.data = data;
2 v% L) g7 n; J. g' g% c! k        }0 i1 T/ a! y4 Q3 @* m
    }% ]' @% Y  v4 A% [" j- N4 R; n5 e' u
}* |' b6 b2 O1 u9 [- w- Z

* h" p4 R6 z1 U
5 `4 M- g5 S, b+ j5 G二、双向链表 12.png ) B, }6 V) v+ F; A0 b" o
双向链表比单向链表稍微复杂一些,它的每一个节点除了拥有data和next指针,还拥有指向前置节点的prev 指针。  q) I3 X4 w, Z1 ]: @) U) y

( w7 i" S$ d8 U: G& m2 {
0 o& P) ?$ e- ~
- E3 [! m2 ~' E3 z; ^4 I6 y2 p$ C
————————————————
* v8 F# p( h$ J5 y. ^: B* m版权声明:本文为CSDN博主「爱做梦的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。) I1 k$ L3 S& P  P5 m* D
原文链接:https://blog.csdn.net/weixin_43124279/article/details/105904468
/ r  |1 e1 J# g3 D% L
: _8 b, p( \2 U! l# v
) _5 j/ a* J! K; h9 J, L1 G

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

2.png






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