) Y: J) v4 n# m& ~5 h% k$ u//为列表创建一个类 ) r7 V. J( z3 c2 O' |- e) [6 dclass SinglyLinkedList{ 4 l0 V, \. p4 h# p) { // 列表有三个属性,头、尾和列表大小 * L- M; N" L: B# U. q2 Y constructor(){ : _$ t/ ^' t* x4 X+ Z this.head = null! q0 d7 Y3 h( S' E8 X
this.tail = null- ~) [6 i# X$ O8 g2 L0 m
this.length = 0 # _; p& [. @6 v+ I" E } & p' a, z8 E+ }; u+ ~: T // 向 push 方法传入一个值作为参数,并将其赋值给队列的尾 6 Y" u8 d6 Y9 \2 m push(val) {$ s0 z9 m- G6 [8 f Z n
const newNode = new Node(val)3 _8 |( d2 `) y) i) D! a( O
if (!this.head){. C- D1 P; o+ q* i5 R
this.head = newNode4 L* g6 D7 j$ r6 Y$ Y. Y
this.tail = this.head 9 o) l5 Z/ f5 P; F ]5 V2 r5 ? } else { H' y) {# o; H0 i' v$ [3 M$ V& f
this.tail.next = newNode / ^$ P4 ]4 M/ x, V/ M this.tail = newNode- p( v4 i7 a0 x0 V
} 7 z& y v' u5 d" a1 K: x this.length++ 8 Q2 K$ j9 X* [3 D7 \4 Q- m return this; b8 h7 Y+ x9 `4 u$ ~
}- y( N* e) h g7 }% i( f
// pop 方法删除队列尾0 J, y) H* L- ?% X) J
pop() {3 v0 O+ ^7 b0 m8 @) b, `/ o4 S! F
if (!this.head) return undefined - m2 g5 Y( R, S1 |7 n$ I: \ const current = this.head0 U. Z% j& Y- Z5 C
const newTail = current ! v8 B; H! U$ F% \4 G$ R0 p% X while (current.next) {. z: m( l: B8 k/ ~
newTail = current " h4 ]: F3 u6 X current = current.next / Z2 u" T3 Y; T' M/ d9 a }& v5 A! u7 Y$ I8 A
this.tail = newTail8 D; g+ M, I" z2 c3 }" T# j
this.tail.next = null5 M8 m! H/ n, y! _' Z
this.length-- 4 \5 c9 {. Y( M5 N# z1 E$ H if (this.length === 0) {3 n7 Q$ l2 I8 {+ |( c
this.head = null% d- H3 i; D* r$ ]# Z& R
this.tail = null 7 c3 k+ l( O2 Z. c) r }) @# v4 ]$ z- h( H/ x M
return current / c8 E% z7 `- O% ]4 X, B }' o: J6 h9 \ g- ~7 ^
// shift 方法删除队列头 r P. F- f& P7 A l
shift() { / K6 d; y' M- e1 } if (!this.head) return undefined ' ^, q' f4 W/ x6 s, W$ d var currentHead = this.head' ?; t; G7 @- {0 k0 D6 V" B3 w
this.head = currentHead.next( C; H0 w& c4 K: R
this.length--5 Z9 h3 J, e' _
if (this.length === 0) {4 [7 m' _5 g5 i6 l/ [
this.tail = null% `8 H- Z6 d5 |$ O8 p, y
} ) ~2 C8 h8 L1 ^! u' ~- D9 y. G# u return currentHead5 U+ t7 n2 z# L/ G: n
}8 E# w) w, I. H; z$ w+ n
// unshift 方法将一个值作为参数并赋值给队列的头 - t7 {- ?2 P% ~, A; r" I unshift(val) { $ ^/ X. u S/ D R$ m0 ^# e9 { const newNode = new Node(val) , b1 _8 j- w1 D( ^ if (!this.head) { % h9 `* h2 \0 s ?3 |2 z) B: a* y ] this.head = newNode ' c" H. S i& d3 S8 o this.tail = this.head / Z$ Z5 o$ ?: S) Z }: f% M) ^( g2 P/ |
newNode.next = this.head2 C) X. i* r5 _
this.head = newNode+ G- \4 ?5 H$ A( _( Z) t6 T& g. C
this.length++ + a5 @2 d0 P, F: ^' q% [ return this% u) Q) ^* q z1 ?- _' b
}' a Q( G g; m# B' ~
// get 方法将一个索引作为参数,并返回此索引所在节点的值" O( j- a& h n( w9 p
get(index) {5 H* [% T' I. i+ r! m/ C% u
if(index < 0 || index >= this.length) return null" x. I) V2 U, {* D* _) J
const counter = 02 ^# X. \) \; A& [3 C% E
const current = this.head& T7 H6 n$ _' w, s! z5 F! ^/ E
while(counter !== index) { 1 C S. z5 [8 r" V% U9 t X) M current = current.next % |1 [, {+ c B/ I" o" W! L counter++& r9 [! z( h" ?% q
} ' e' [) i7 b3 H$ _7 @6 h4 O return current + n P8 B( O$ R v: t# y# N# ] } % S7 e( t2 y6 f, B" y // set 方法将索引和值作为参数,修改队列中索引所在的节点值为传入的参数值# ]. q; r6 u* d. \$ m
set(index, val) {% b- {( O3 A* _' C5 B( i+ l {
const foundNode = this.get(index)7 t* ]$ y; W4 _6 h( e% R0 d5 \6 y
if (foundNode) {; d- J: Q2 P! q6 A
foundNode.val = val, c" Y4 R$ G4 `
return true8 e5 h& Q; J h/ Z4 u0 C
} " G+ X$ o( u8 z# V return false. K' M+ v# b) L. Q) ^) ]( \6 t
}7 N* |$ @/ L* T$ D7 f0 p
// insert 方法将索引和值作为参数,在队列索引位置插入传入的值: t& ]2 _* c" I$ g4 s; a
insert(index, val) { $ y3 F( _% I5 P# j# u Z: l if (index < 0 || index > this.length) return false5 z1 w$ @& G6 t& O5 [5 r
if (index === this.length) return !!this.push(val) 5 S, b. |0 X1 w6 n if (index === 0) return !!this.unshift(val)/ u6 K6 R" R4 O0 D# G! {
; r- E0 I3 k; p2 p) b3 T8 r const newNode = new Node(val) ! q- E S9 O1 |4 j% ~; s const prev = this.get(index - 1)/ ~. B/ e' A; L/ k
const temp = prev.next ; [, h1 {- ^8 L3 J: M prev.next = newNode! W. K% r1 x1 j B& e2 e4 _
newNode.next = temp( @# G8 W( ~+ @
this.length++* b9 Y v' R. a0 l( x; Y7 \) b7 U7 S
return true" l8 d$ p- b; f+ C5 j N! Z4 v
} 2 o' o9 r4 m2 i% V v; S // remove 方法将索引作为参数,在队列中删除索引所在的值 : M3 d L/ v% c0 Y! a0 g remove(index) {- I. F2 U- c; {0 P( o( _1 K1 V
if(index < 0 || index >= this.length) return undefined0 o8 t9 F# ~( v: u% \
if(index === 0) return this.shift()- Q) V/ ^) l1 O$ z* x
if(index === this.length - 1) return this.pop() * _- {! i/ P- Z7 R/ u const previousNode = this.get(index - 1)' C2 z) ^( U# q
const removed = previousNode.next ; c2 Q2 J: W8 y previousNode.next = removed.next % R) g2 d1 l1 p0 u! N this.length-- 0 c6 l9 J) e0 L) m% R" i- x8 e( C return removed( q/ {" |# t( P& @ O% i+ e. d
} 2 ]% y" P) a/ v1 F, X' N4 H // reverse 方法反转队列和所有指针,让队列的头尾对调 ' Z# i- I# u8 f4 w reverse(){# G, l' z+ c, n- b6 j4 v! x9 Y
const node = this.head ; x6 n6 ?" H, o1 V/ j this.head = this.tail$ T0 U# r( O/ I
this.tail = node' J* |, P( P; Q7 M* Q% [
let next , B# \8 L: H; a F( j const prev = null- C1 U: m7 V2 [, Z1 O9 `
for(let i = 0; i < this.length; i++) { 2 i2 c4 {9 o: q: @/ V next = node.next& p: v% A/ Q4 @- }0 e
node.next = prev " ?2 M: W3 P: `( ~) u/ M" w0 ~: g prev = node ! V. W. w9 \# V' z" F2 g+ b+ v) } node = next* N4 N2 Z# F- B1 l, K/ Z! u* A
}( O' f0 o2 D, w! Y5 t3 f9 E
return this6 h, w# X& n- f; M& `9 F2 V6 W( D
} 6 J- _6 h I j' f9 s3 N; a" i} ; B- M4 i+ h2 D( b单链表的复杂度为:插入 - O(1)删除 - O(n)查找 - O(n)访问 - O(n)双链表如上文所述,双链表和单链表的区别在于双链表的前后两个节点之间由双指针相互连接,而单链表只有一个指向下一个值的指针。双指针使得在特定场景下双链表比单链表的表现更好,但是也增加了存储空间的成本(存储双指针比单指针更占位置)。完全实现双链表的代码类似于:// 创建列表节点的类2 g* U+ B/ D9 R( _- {. Y2 L
class Node{ 8 L2 D7 y: S/ ]9 N2 J- _ // 每一个节点包含三个属性,其值,一个指向上一个节点的指针,一个指向下一个节点的指针7 v F( ~# L# y
constructor(val){& u3 L3 b1 w. i1 d( m7 B
this.val = val; ; _0 r5 H% X8 r+ p5 Y+ A' ~9 a this.next = null; ) k7 w K+ O2 f. R% D( `+ G this.prev = null;! L0 X' q+ V T& C
}0 k6 j j3 j7 U% t4 K
}; B' e8 [" B+ @( [, P) {
' Y$ d2 i4 E* m+ \) X) U% u
// 创建一个列表的类9 r5 k6 d5 z+ i8 [7 `; y
class DoublyLinkedList {1 y! [5 Z* `% S, j1 ~2 ]2 }6 z2 C9 X2 I
// 列表有三个属性,头,尾和列表的大小 8 b4 W/ I" a" l I constructor(){+ _+ b. _5 ^3 b$ r+ N1 M
this.head = null- {8 W* f1 L9 L7 n3 c \% k9 y1 ?
this.tail = null; c9 z. V! t! j Q! t9 k
this.length = 0: R+ }# u) G, \$ I! h
} 0 F7 U* G0 ~8 t8 `7 } // push 方法将值作为参数并赋值给队列尾6 K8 ?1 P& y: F7 t, W
push(val){ 9 F: {# l. O' u const newNode = new Node(val)! t1 ^; A, [+ P: y. j: H
if(this.length === 0){ Q5 t: W! v' g" H: Z, H5 W this.head = newNode 5 o7 l M0 R) A3 o2 e- o this.tail = newNode7 L3 C2 q( z p; w
} else {- ? x1 I7 E9 E s0 j* E/ }5 N$ J
this.tail.next = newNode ! b$ C0 U) r. _; L3 X+ v7 p newNode.prev = this.tail X' s7 C, F) @6 B4 ^
this.tail = newNode& @: q8 F, _' v& G
}" H5 a0 P6 _% G- o4 p! m
this.length++4 j! [5 _. ?8 R9 ~4 o9 Q' q
return this 1 V9 f' X$ N2 b( ]: O0 ~ } : h% Z) z# H, W8 u( w // pop 方法删除队列尾; Y* v$ s" Z9 S m6 H3 O( F
pop(){ % p8 y4 r6 A c: j$ l# w if(!this.head) return undefined. h; L6 i, l3 z, V* Y8 I
const poppedNode = this.tail9 p! Y7 A# S2 j2 Y8 F5 J* O) ]+ g
if(this.length === 1){ : L7 r8 [5 a& [( y# E this.head = null' U g8 g5 O/ D6 l- K* {" v! j
this.tail = null! W+ J& G8 u1 c0 T& u$ S" ^
} else { & s# c) y" R( @' K9 e+ `) l. M this.tail = poppedNode.prev9 a: U2 B Y' o& ` z7 Y& ~
this.tail.next = null + g. ^0 ^( R) T/ k0 a; F X; h poppedNode.prev = null( Y# S+ h. |/ s. }2 \/ f) |
} # u9 C$ H7 q5 i% y. v8 n. {/ U this.length-- ! i, i$ c. B- ]) t return poppedNode( f9 g* J ~/ S5 ~
}) |) r( l. z: V, w. O- {
// shift 方法删除队列头: N7 X" _1 f7 J
shift(){ % k9 ~2 h9 y1 Y; n+ u& j; G/ n if(this.length === 0) return undefined E1 V( L% {) M; z
const oldHead = this.head % {; O' ^9 R3 m) y: m- O4 j if(this.length === 1){8 O% v j$ \5 T' S
this.head = null ( \% \6 G6 j) [/ N this.tail = null 0 L: L" L0 c1 a1 G: e5 G& b6 U3 S4 h } else{1 h: I l2 d F8 ?/ T
this.head = oldHead.next 1 A8 R0 Z3 _" E this.head.prev = null ) e Y& f+ a0 W: t oldHead.next = null$ x( m: u8 Z9 l5 l4 e t
}* u O* U) e0 j
this.length-- `4 u' f: N1 N: g) l return oldHead8 E$ I- c9 c/ J3 T8 W' j- V3 l
} 9 g M; q7 ?0 B$ z4 I4 v // unshift 方法将值作为参数并赋值给队列头 - T6 G d$ F. _$ `* f. s unshift(val){ 6 g; ~6 x, z3 x const newNode = new Node(val) ! {9 q+ T) I6 s- @ if(this.length === 0) {. E% q4 N6 j) W
this.head = newNode: K4 O* g5 x: u0 Z
this.tail = newNode + ^ B4 _3 s2 G6 T( e: |1 w } else { ' }' p7 t/ o' A$ c4 v this.head.prev = newNode : b! Q" e( A, Y newNode.next = this.head - C# @3 x$ \) K$ p) V this.head = newNode; m, v% x9 ^7 P) o# C- V) f+ c
} ! b8 G. K: u/ _5 B$ B$ L7 ^6 T2 j6 c this.length++4 `# k9 J; x$ L: ~6 `/ B$ \
return this ( n' E% V. o, ~- B } ' u2 v) m3 J% w- E# j" a // get 方法将索引作为参数并返回队列对应索引的值 " ], u b. y$ c. [) H get(index){ ! g7 \5 Q- c2 z6 m if(index < 0 || index >= this.length) return null ! _ ^' \" J* ]3 P let count, current 3 U5 b: \/ Q, ]2 p0 C( U7 F5 v2 y& x1 I if(index <= this.length/2){ 3 [4 b/ S7 a! V1 I count = 0 # f( |8 ~, b+ c3 a r: c/ h- }3 E current = this.head % l( @9 Q, U5 X% Z& Y0 Z( i while(count !== index){ 5 ]) }1 ~7 i8 C6 \" \ ] current = current.next 2 C6 [7 X/ M1 p9 N6 ~$ M! J, W count++' {7 v! S( a8 P3 r- l+ P8 j# y) ]
} ~! ~' e* D( A4 R
} else {7 z" o* s, W# J
count = this.length - 1 : D' r$ M: C4 j1 I, |2 n current = this.tail' h6 d6 U$ `9 j. _+ E
while(count !== index){ ) ]: J; I8 b9 ~2 F8 O current = current.prev ) @. F) r+ D7 N9 j) d count--" o# b$ b" r' S
} - ?0 U, Z! ~% {+ g }% U F( y: |/ E6 f1 g; ?, d/ t
return current8 w9 v/ s% @) f2 v0 {" t/ A, y" z- l/ |& x
}+ M; H6 ]# ^7 G' A
// set 方法将索引和值作为参数,修改队列中索引所在的节点值为传入的参数值; Z# F* J7 E! ]. {( B V
set(index, val){8 n$ k4 o" [) J# W" k7 q" U5 O
var foundNode = this.get(index) , J6 W/ w0 U. X0 I if(foundNode != null){1 v' t0 |0 g8 z1 Y6 s8 N ^& U# d! R
foundNode.val = val; G1 D: e- \; R6 ^+ S
return true8 v' T' V/ \$ J2 Q
} 5 _0 Y' e* q. P$ r8 X4 w return false4 R5 C9 G/ u9 c8 F
}3 v; l9 h! ]/ I* h: ^" Z! [% h" v/ K% v
// insert 方法将索引和值作为参数,将值插入队列响应索引位置7 W# R, ~9 ~* J& a' G
insert(index, val){9 h$ _5 U; x. f6 }# l
if(index < 0 || index > this.length) return false . X: Z% ]3 {8 B! _3 K2 R5 ] if(index === 0) return !!this.unshift(val) # K6 r( P9 s$ n4 p. a4 t8 h! _) l if(index === this.length) return !!this.push(val)& B; I9 u$ J1 }9 M: C! o+ z% l k" i
& w6 c/ w& B5 ~6 { var newNode = new Node(val) ( N; R- `+ H: g4 g- A6 n4 I var beforeNode = this.get(index-1) 7 V8 U; q7 H- K! c' v& h var afterNode = beforeNode.next # u+ t) H2 B6 p0 G 9 U1 s$ f' j3 ?1 t* R# {, f# y) f beforeNode.next = newNode, newNode.prev = beforeNode+ L7 v6 G3 O9 O# g D) C, E
newNode.next = afterNode, afterNode.prev = newNode/ p3 u: ~, c9 H' w
this.length++ , E, [" T% |! C5 {3 ?3 e8 p return true, ?9 j1 c5 z- x0 x4 a `& F# a3 }5 G( W* L
}* @; {0 I+ T# X" [, m" p5 \
}" M+ j" d; H+ j
双链表的大 O 表示法为:插入 - O(1)删除 - O(1)搜索 - O(n)访问 - O(n)树树是一种以父子关系相连的节点之间的数据结构,也就是说节点之间相互依赖。 ) n& p0 ]% v# A8 p( W(, 下载次数: 256)
上传
点击文件名下载附件
3 g+ g2 s1 v' T9 w. d 树结构树由根节点(树的第一个节点)开始,其他所有由根发展出来的节点被称作子节点。树结构最底部的节点没有“后代”,被称为叶节点。树的高度由父子节点相连的层数决定。和链表及数组不同的地方是,树是非线性的,程序可以在数据结构内选择不同的方向遍历数据,从而得出不同的值。而在链表或者数组中,程序由一个端点开始遍历到另一端点,每一次都重复同样的路径。构成树结构一个重要的要素是仅从父到子连接的节点是合法的。“亲属”之间或者由子向父节点是我连接都不被允许(这样的连接会形成图表,是另一种数据结构),另一个重要的要素是树只能有一个根节点。程序中使用树的场景有:DOM 模型人工智能中的情景分析操作系统中的文件夹有不同类型的树,每一种类型的树的值都遵从不同的模式而组织起来,这样也就适用于不同的解决问题的场景。最常见的两种树是二叉树和堆。二叉树二叉树是每个节点最多只有两个节点的树结构。 * I6 M; e2 D4 o; O& ]1 F(, 下载次数: 269)
上传
点击文件名下载附件
1 o% K N5 R- T. p0 t 二叉树二叉树的一个重要使用场景是搜索。用于搜索的二叉树被称为二叉查找树(BST)。BST 和普通二叉树类似,只是内部的数据结构被排列成易于搜索的结构。在 BST 中的值是排过序的,所有节点的左子节点的值要小于父节点,所有节点的右子节点的值要大于父节点。 ' P! E5 t! w1 V/ C- X7 @8 [& c! ~8 A(, 下载次数: 261)
上传
点击文件名下载附件
J7 s4 m" Y8 t+ T
二叉查找树这样给值排过序的数据结构非常适合做搜索,因为树的每一层都可以对比是比父节点大还是小,在对比的过程中,我们可以逐步舍弃掉一半的数据得到最终我们需要的值。当插入或者删除值的时候,我们的算法会进行如下步骤:检查是否存在根节点如果存在根节点,检查这个需要添加或删除的值是比根节点大还是小如果比根节点小,则检查左边是否有节点,并重复上面的步骤;如果左边没有节点,则将这个节点在当下位置添加或者删除如果比根节点大,则检查右边有没有节点,并重复上述步骤;如果有变没有节点,则将这个节点在当下位置添加或者删除在 BST 中查找与上述方法类似,但是没有添加或者删除值,取而代之的是与节点比较我们搜寻的值的大小。树的大 O 复杂度呈对数(log(n))。但是需要注意的是,想要实现这样的时间复杂度,必须保证树结构的每一步都是左右对称的,这样我们才可以在搜索的过程中“丢弃”一半的数据。如果在任意一边存储的值更多,树结构的搜索效率就会打折扣。实现 BST 的方法如下:// 我们创建树的节点 4 G0 P8 ]3 s0 Q$ lclass Node{ 4 w5 D# V& r; }& G- J' x5 G // 每一个节点有三个属性:其值,以及指向左节点的指针和指向右节点的指针$ _+ o2 X3 V. ^- R
constructor(value){ - @* D7 [: G# W9 H/ b' f; ` this.value = value - ^9 [: ~; q8 k' }- D% w this.left = null% N7 [8 u) R9 ^6 O
this.right = null0 W. d. i, p; ^9 E- W
} 1 E1 w/ |7 f9 Q" v/ x0 L) }1 g} # N* T5 q( u; s3 _& F' ~# R" j# z// 创建BST的类 7 j/ [8 W# j1 ~( M1 G! L5 Nclass BinarySearchTree { ! L, |$ v4 k) M) h // 这个树只有一个属性即根节点5 N6 h D( I; r% J; D! j- g! |$ x
constructor(){4 |& r! L' r8 F6 Y0 F9 I& Z
this.root = null & A/ y: E- p* N; } } ( ?3 Z" Q& k. e- `5 N3 W // insert 方法将一个值作为参数,并将值插入树对应的位置% V* T/ U* t: O7 [6 |5 |! }
insert(value){ * a. K' M l) \2 a! i8 V const newNode = new Node(value) + J# i+ v" C! j9 u if(this.root === null){3 [3 V: T1 T8 a' h
this.root = newNode) A5 a$ a5 `( U( }8 V. y% q
return this5 @ T9 b/ M/ _( y, H
} 2 S) y$ w" ?) |; a2 Q let current = this.root- i+ X: ]$ j, O k- d" J
while(true){ ^5 M' ]- S, M" F0 @
if(value === current.value) return undefined % ~! h z5 y) h% q, \5 y- M if(value < current.value){ * q8 e/ Q' I7 ?3 G4 _" K if(current.left === null){+ [% G+ ~8 c7 C" S- g
current.left = newNode . F/ y9 r; U H8 |5 N3 E9 ] return this% W/ X8 {, } ]7 @( ^" F
} 0 n, P1 ^7 V' K current = current.left . k8 p/ F4 Y4 B* \1 a: l } else { ( Q8 e# Q/ n; U. m. j: K1 | if(current.right === null){ + k. s$ s* X9 ^& x/ m6 E current.right = newNode0 V6 N1 W+ ~" G/ k5 A: g0 }+ t
return this! {( F9 i/ `* T6 z% ^+ X/ m
} ( p3 r. T$ l8 o5 P7 i2 E current = current.right3 f# @8 [/ r: p. |* ^: K
}; V; K6 O% } j) f+ V1 P
} 5 i+ D& |# Y! o" r$ C. C h }( A+ g; k1 j2 X- w
// find 方法将值作为参数,遍历树寻找对应的值2 L2 q5 j. R* c$ l- \8 o) t
// 如果找到了,返回找到的值,如果没有找到,返回undefined 2 o1 \& \. R, j& E+ x find(value){ ! w3 z3 b# Q- {" D. G7 L1 Z if(this.root === null) return false 4 c9 z3 N4 G- {& x/ I2 q. e let current = this.root, ; a8 b9 [; C) M6 S" M c found = false 2 d& A, \; T6 z/ W$ I while(current && !found){ 1 B3 O" b) h5 S# A; d. N if(value < current.value){ 1 d: L d# |0 G+ ?0 H: R; O) k current = current.left; L( T2 `0 _' }
} else if(value > current.value){7 z9 t, c: J6 ~% Z: i
current = current.right/ [9 b9 V6 L, S7 ~7 ?, p& r- \
} else { ( ^5 R4 l4 _3 G& _/ c$ |% Q found = true ; d8 O/ T2 S5 E: a# T }% `1 l4 Q$ m6 r7 `4 ~
} # L4 g: @/ l0 a2 y if(!found) return undefined3 w' Y; R. q8 @6 ^, L. G6 ?$ f* ?: W
return current " _9 N1 U1 ?# W o) n" z# T } , c, N1 m* D1 J // contain 方法将值作为参数,如果找到树中对应的值返回 true,如果没有找到则返回 false6 M+ D( q, K$ m. I6 W2 q" F( C
contains(value){! J/ p l3 s' c, m8 e0 J' J
if(this.root === null) return false ) J' i- r" h3 ?- a8 i let current = this.root, 9 k+ |. z' J6 i4 e8 a- @ found = false$ t) u1 ? a3 O: O. x
while(current && !found){* ]! u, h0 D8 ]/ [2 [" Z# g0 w+ w# E" X8 N
if(value < current.value){ w4 r4 ]! f" |1 f" D8 l2 v, c
current = current.left; l" c5 g: c p! T
} else if(value > current.value){+ ~+ r0 f5 E& g3 |# i: D3 x' x
current = current.right" G) t' ^" }1 B! i- c! @
} else {+ C' x) `3 G( y- F7 q8 |
return true9 @7 e9 `) c5 v0 b( k2 R
} ! \# [& ?0 z( i9 C+ z } ! u+ Q* u* W7 w' Q5 Y a1 q. L return false. A8 R p& P9 }( c' v
} ) R# l! ]4 G$ V' X% A}/ u; d/ I5 r4 t; v7 r
堆堆是有特殊规则的树结构。主要有两种形式的堆:最大堆和最小堆。在最大堆中,父节点的值必须比子节点大;在最小堆中,父节点的值必须比子节点小。 0 w4 J0 w2 @5 }0 ~(, 下载次数: 256)
上传
点击文件名下载附件
% R# l3 p) `3 e, p 最大堆; I( b: K; Z8 E (, 下载次数: 246)
上传
点击文件名下载附件
6 e6 s) j1 r- ], M, b 最小堆堆结构的规则不适用于相邻的两个节点,也就是说在同一层的节点除了必须比自己的父节点大或者小,不需要遵循其他规则。另外,堆越紧凑越好,也就是每一层都尽可能填满空位,新的节点首先添加到左边。堆,特别是二进制堆,通常被用来解决优先队列问题,也被运用到知名的算法问题——戴克斯特拉算法。优先队列是一种数据结构,在这种结构中,每一个元素都被关联了优先级,优先级高的元素优先展示出来。图图是一种有一组节点相互连接的数据结构。和树不一样的是,图并没有根或者叶节点,也没有“头”或者“尾”。不同的节点随机关联在一起,之间并没有父子关系。" O% H. r/ e, C7 V# q' Y4 G (, 下载次数: 274)
上传
点击文件名下载附件
/ `$ S" W7 _8 D5 W
图图经常被应用于:社交网络地理定位推荐系统根据节点之间关联的特征,可以把图分成不同的类别:有向图和无向图如果节点之间没有的关联没有定义方向,我们就称这个图为无向图。在下图中我们可以看到节点 2 和节点 3 之间的关联没有方向性,我们可以从节点 2 到节点 3,也可以从节点 3 到节点 2。无定向意味着节点间的连接是双向的。 4 V E, Z' g3 T# T(, 下载次数: 273)
上传
点击文件名下载附件
" S, s; c" S# X+ S, p; P 无向图你可能已经猜出来了,有向图就是完全相反的。让我们再次使用上面的图,这时节点之间的连接是有固定方向的。在这幅图中,你可以由节点 A 到节点 B,但是不能从节点 B 到节点 A。6 R/ A/ j1 X+ p0 y: P