点击文件名下载附件
A5 w7 g7 v P* |, l+ Q4 b3 a 二叉树二叉树的一个重要使用场景是搜索。用于搜索的二叉树被称为二叉查找树(BST)。BST 和普通二叉树类似,只是内部的数据结构被排列成易于搜索的结构。在 BST 中的值是排过序的,所有节点的左子节点的值要小于父节点,所有节点的右子节点的值要大于父节点。 1 L. n* k+ `! C$ Z(, 下载次数: 277)
上传
点击文件名下载附件
$ f. a4 s, v5 X3 b 二叉查找树这样给值排过序的数据结构非常适合做搜索,因为树的每一层都可以对比是比父节点大还是小,在对比的过程中,我们可以逐步舍弃掉一半的数据得到最终我们需要的值。当插入或者删除值的时候,我们的算法会进行如下步骤:检查是否存在根节点如果存在根节点,检查这个需要添加或删除的值是比根节点大还是小如果比根节点小,则检查左边是否有节点,并重复上面的步骤;如果左边没有节点,则将这个节点在当下位置添加或者删除如果比根节点大,则检查右边有没有节点,并重复上述步骤;如果有变没有节点,则将这个节点在当下位置添加或者删除在 BST 中查找与上述方法类似,但是没有添加或者删除值,取而代之的是与节点比较我们搜寻的值的大小。树的大 O 复杂度呈对数(log(n))。但是需要注意的是,想要实现这样的时间复杂度,必须保证树结构的每一步都是左右对称的,这样我们才可以在搜索的过程中“丢弃”一半的数据。如果在任意一边存储的值更多,树结构的搜索效率就会打折扣。实现 BST 的方法如下:// 我们创建树的节点 Z/ p: R" L8 F. x, O
class Node{ 9 V# q- p( x+ ]& j1 w5 x // 每一个节点有三个属性:其值,以及指向左节点的指针和指向右节点的指针* b4 h; D0 _( |5 x' J0 ?7 V% [
constructor(value){" g3 Q3 @- h" t: o
this.value = value 8 l2 L2 ~' _. | this.left = null 6 A4 m3 q5 f9 T- @5 b1 f this.right = null 5 g1 P6 _% b" b9 v7 b) j- X& T# X } . i+ y* R( e3 ?3 ]0 [9 w: A} % {7 T9 f# A$ T! O3 o3 ?9 W// 创建BST的类 ; @/ y% G0 O% u$ X3 g3 j: uclass BinarySearchTree { + D/ [. w- _, S7 {8 I // 这个树只有一个属性即根节点: K3 e {# D" _/ T( e) J
constructor(){ $ P; f: v! {7 @) ^& n% Y this.root = null ' s* [ L$ h8 g; K A M0 F } ! @7 C1 v1 K3 V: {3 c8 p+ E2 s // insert 方法将一个值作为参数,并将值插入树对应的位置( b1 ^9 s+ T2 n1 K
insert(value){ - F" r$ o! Y4 y; _4 @9 c# z3 l const newNode = new Node(value)7 H7 T/ O: |8 |
if(this.root === null){ : D4 @3 _ E3 O" b; K( y this.root = newNode % B4 e$ h' @2 l9 {. j+ ^) n return this p1 e" s$ m8 z; e7 k0 T `
} d% z3 w/ T& A1 e# \# b4 W/ B3 i let current = this.root # f! y0 o. L. \4 X while(true){ # R& I! w& f/ ^# W* D$ [4 G$ N { if(value === current.value) return undefined " P/ h' y5 w0 l% R1 ^ if(value < current.value){ 4 F$ K0 y3 ~: i9 Y& n7 U# c$ X. W if(current.left === null){* w2 |) X# l( z1 b" o. K
current.left = newNode @5 p7 ]4 w6 Y3 I( b3 t return this- e: G+ Y! s+ C8 F6 {8 ] o/ U
} / A5 |9 z0 W5 s2 B5 s% W current = current.left1 X5 Z% e' v) t7 @$ l5 H
} else {7 o& [1 k1 |5 r1 V5 N3 ^ x
if(current.right === null){ R% K& r* n" j$ ]
current.right = newNode$ W& P% O7 ^4 G8 C9 S
return this ) l: e# W9 }7 c) t% g } ! w S% a m) D: }. Y: @( c+ l
current = current.right 4 w8 Q. M2 n5 @9 V; ~- d5 f; R5 J } 1 @. R; w$ S3 A; V& a } ; r& O) G' n! q1 c2 Y }* z) b# o: T% a6 @+ }/ @
// find 方法将值作为参数,遍历树寻找对应的值 : u: Q( V. w$ q, l6 } // 如果找到了,返回找到的值,如果没有找到,返回undefined5 f/ _ I: Z% P
find(value){% y0 H8 P) k1 C' W) S
if(this.root === null) return false 6 V. t+ S8 [! t! P6 c let current = this.root,9 s9 n( h- `2 f$ G: C' B& E2 B
found = false3 [ M/ a! j$ p7 V2 S
while(current && !found){7 o3 N7 c# A9 L
if(value < current.value){* l/ O+ N! r3 g3 g9 L& q9 T
current = current.left/ _* ], ^) I$ c1 S
} else if(value > current.value){ % p8 S+ X0 c, F$ |: N" L) d. ` current = current.right1 ?4 s; Y6 E1 P6 b7 M
} else { 0 p3 [4 {9 }" i9 I P1 M$ T found = true, B$ {" ^( U S
} * e+ N/ _. X2 p ] }- h2 `- P0 c0 L
if(!found) return undefined/ A: O! o! P3 |8 F# N2 B* h1 j* q
return current - k9 @$ d' i0 } } ) F3 j3 I/ W; W- V; }/ F1 `% ~ // contain 方法将值作为参数,如果找到树中对应的值返回 true,如果没有找到则返回 false 3 Y. d7 l0 a! y$ b8 p1 J) N0 [' [ contains(value){ 8 X. z0 H0 o7 Z0 ]' H* w if(this.root === null) return false ; p5 a6 @5 }- R3 J. b; z5 f( b let current = this.root, & V: u. M w( g# R+ m& F! ^ found = false$ _+ B1 M3 f+ r$ _, w" D4 W
while(current && !found){- V/ K; b4 p' f1 Z( n& W
if(value < current.value){ * ^' D$ g( B' r% o) y( B% c( e current = current.left 2 U4 O2 F% @6 O; Z. D4 Y } else if(value > current.value){" b; `8 P+ R, l0 X5 e/ R
current = current.right8 P/ O; o5 S. y& u' N1 ~. W9 L
} else { - o' [: B/ f( y7 E4 a3 ^$ u" U return true8 `0 U) {# W- S3 x7 c
} , \/ h5 B: G7 X0 v } 9 `) c" I5 B1 m r. b return false: G% \8 ?5 X( N& T% S: P% @
}! @' _+ c3 ]. n, q+ u
}$ |' K6 M F7 G1 Y5 p
堆堆是有特殊规则的树结构。主要有两种形式的堆:最大堆和最小堆。在最大堆中,父节点的值必须比子节点大;在最小堆中,父节点的值必须比子节点小。 " a! j9 d, r9 K" j7 b# }. k(, 下载次数: 274)
上传
点击文件名下载附件
- J- s" Q, G* [* ^& [ 最大堆; E: B [ w9 N (, 下载次数: 259)
上传
点击文件名下载附件
: t1 u8 M9 g: K
最小堆堆结构的规则不适用于相邻的两个节点,也就是说在同一层的节点除了必须比自己的父节点大或者小,不需要遵循其他规则。另外,堆越紧凑越好,也就是每一层都尽可能填满空位,新的节点首先添加到左边。堆,特别是二进制堆,通常被用来解决优先队列问题,也被运用到知名的算法问题——戴克斯特拉算法。优先队列是一种数据结构,在这种结构中,每一个元素都被关联了优先级,优先级高的元素优先展示出来。图图是一种有一组节点相互连接的数据结构。和树不一样的是,图并没有根或者叶节点,也没有“头”或者“尾”。不同的节点随机关联在一起,之间并没有父子关系。3 n. @" o2 ~& D (, 下载次数: 290)
上传
点击文件名下载附件
( D8 g( J! f' Q _6 G 图图经常被应用于:社交网络地理定位推荐系统根据节点之间关联的特征,可以把图分成不同的类别:有向图和无向图如果节点之间没有的关联没有定义方向,我们就称这个图为无向图。在下图中我们可以看到节点 2 和节点 3 之间的关联没有方向性,我们可以从节点 2 到节点 3,也可以从节点 3 到节点 2。无定向意味着节点间的连接是双向的。+ U. |0 p/ F6 k( ~5 ^0 y/ W- g (, 下载次数: 293)
上传
点击文件名下载附件
( f8 y0 U6 Q W X' }5 B' s
无向图你可能已经猜出来了,有向图就是完全相反的。让我们再次使用上面的图,这时节点之间的连接是有固定方向的。在这幅图中,你可以由节点 A 到节点 B,但是不能从节点 B 到节点 A。( \4 h* a+ K4 ]: o* A z P/ S
, R/ E. I; K4 [9 J. k) s 有向图加权图和非加权图如果节点之间的连接被分配了权重,我们就称其为加权图。权重仅分配给了节点之间的连接,仅和连接相关,不和节点相关。在下面的例子中我们可以看到,节点 0 和节点 4 之间连接的权重是 7;而节点 3 和节点 1 之间的权重是 4。 ! r' i2 `+ w d7 |7 T% x9 W/ E(, 下载次数: 256)
上传
点击文件名下载附件
6 b* G$ N3 c/ q. C2 C: W 加权图想要了解加权图,可以想象你需要向用户展现一个标注了不同地点的地图,你需要告诉用户从一个地方到另一个地方需要花多长时间。加权图就可以用来表现这个场景,你可以使用节点来存储地点的信息,节点之间的连接就是两个地点之间的道路,连接的权重代表从一个地点到另一个地点的物理距离。 ' V# x5 s L" s(, 下载次数: 347)