数学建模社区-数学中国
标题: 【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
& _# ?) 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
5 A& S2 m( @ C- T6 |8 m* q% i$ o2 o6 T; J3 o& @3 X
图中的箭头代表链表节点的next指针。
链表的基本操作1. 查找节点在查找元素时,链表不像数组那样可以通过下标快速进行定位,只能从头节点开始向后一个一个节点逐一查找。
$ ~/ 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. 更新节点
" 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种情况。
- 尾部插入
- 头部插入
- 中间插入
/ ^- e1 s4 D! _( C6 C8 B4 g
3.1. 尾部插入尾部插入,是最简单的情况,把最后一个节点的next指针指向新插入的节点即可。
: ]1 J$ c) F P' K* B; B3 I* d' D8 N" M
9 k6 R3 y4 T' G. A& L" w7 [
3.2. 头部插入头部插入,可以分成两个步骤。
- 第1步,把新节点的next指针指向原先的头节点。
- 第2步,把新节点变为链表的头节点。
3 @& T4 H4 g2 d( ]- ?
) }) ?! p% l) E7 r$ Y( [4 s
+ A$ h q6 O" b7 _4 u
3.3. 中间插入中间插入,同样分为两个步骤。
- 第1步,新节点的next指针,指向插入位置的节点。
- 第2步,插入位置前置节点的next指针,指向新节点。& X( I; f* t% p9 g; ?5 g; K: Y2 E
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种情况。
- 尾部删除
- 头部删除
- 中间删除
% Y1 x' }7 _2 x- u* g: O
4.1. 尾部删除尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即
. k$ O! i7 B, k3 E8 e: Q可。
7 u1 _% h& g: o6 p' k6 M
# B. ^* |; ^! T* Y4.1. 头部删除头部删除,也很简单,把链表的头节点设为原先头节点的next指针即可。
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删除元素的下一个节点即可。
( 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 |二、双向链表
- 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)
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) |
Powered by Discuz! X2.5 |