数学建模社区-数学中国
标题: 【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 ?
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
! |. W# N5 D. l1 s k. l
, K! F# S8 Z% P图中的箭头代表链表节点的next指针。
链表的基本操作1. 查找节点在查找元素时,链表不像数组那样可以通过下标快速进行定位,只能从头节点开始向后一个一个节点逐一查找。
/ 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. 更新节点
/ [$ 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种情况。
- 尾部插入
- 头部插入
- 中间插入/ @" S( |. o4 d
3.1. 尾部插入尾部插入,是最简单的情况,把最后一个节点的next指针指向新插入的节点即可。
- ?$ L' H0 o$ J8 S+ R
. z8 T1 |/ | g D
3.2. 头部插入头部插入,可以分成两个步骤。
- 第1步,把新节点的next指针指向原先的头节点。
- 第2步,把新节点变为链表的头节点。
0 z+ {8 @7 |! b* w; T
7 v* w% f/ {/ Y4 @. ^8 A! K. x1 T1 r5 E* H% L' Y7 p, m
3.3. 中间插入中间插入,同样分为两个步骤。
- 第1步,新节点的next指针,指向插入位置的节点。
- 第2步,插入位置前置节点的next指针,指向新节点。$ _8 l4 l: }' h) |' k& {
* 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种情况。
- 尾部删除
- 头部删除
- 中间删除
- J5 m2 _/ u- F" q# t+ v
4.1. 尾部删除尾部删除,是最简单的情况,把倒数第2个节点的next指针指向空即5 D" p& H$ i9 l6 B
可。
' Y1 m% m& b# G( D$ f5 q& p! {1 h
4 F' q E, d3 M+ }* v4.1. 头部删除头部删除,也很简单,把链表的头节点设为原先头节点的next指针即可。
" 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删除元素的下一个节点即可。
$ }! 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二、双向链表
) 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)
| 欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) |
Powered by Discuz! X2.5 |