1+ // 线段树
2+ module . exports = class SegmentTree {
3+ constructor ( data , merge ) {
4+ this . data = data ;
5+ this . tree = [ ] ;
6+ // 指定节点的合并业务
7+ this . merge = merge ;
8+ this . buildSegmentTree ( 0 , 0 , data . length - 1 ) ;
9+ }
10+ // 在treeIndex的位置创建表示区间[l...r]的线段树
11+ buildSegmentTree ( treeIndex , l , r ) {
12+ if ( l === r ) {
13+ this . tree [ treeIndex ] = this . data [ l ] ;
14+ return ;
15+ }
16+ let leftTreeIndex = this . leftChild ( treeIndex ) ;
17+ let rightTreeIndex = this . rightChild ( treeIndex ) ;
18+
19+ let mid = l + Math . floor ( ( r - l ) / 2 ) ;
20+ this . buildSegmentTree ( leftTreeIndex , l , mid ) ;
21+ this . buildSegmentTree ( rightTreeIndex , mid + 1 , r ) ;
22+ this . tree [ treeIndex ] = this . merge ( this . tree [ leftTreeIndex ] , this . tree [ rightTreeIndex ] ) ;
23+ }
24+ // 返回区间[queryL, queryR]的值
25+ query ( queryL , queryR ) {
26+ if ( queryL < 0 || queryL >= this . data . length || queryR < 0 || queryR >= this . data . length || queryL > queryR )
27+ return ;
28+ return this . __query ( 0 , 0 , this . data . length - 1 , queryL , queryR ) ;
29+ }
30+ // 在以treeIndex为根的线段树中[l...r]的范围里,搜索区间[queryL, queryR]的值
31+ __query ( treeIndex , l , r , queryL , queryR ) {
32+ // 节点左边界和右边界都与想要查找的重合
33+ if ( l === queryL && r === queryR )
34+ return this . tree [ treeIndex ] ;
35+ let mid = l + Math . floor ( ( r - l ) / 2 ) ;
36+
37+ // 以treeIndex的节点为[l...mid]和[mid+1...r]两部分
38+ let leftTreeIndex = this . leftChild ( treeIndex ) ;
39+ let rightTreeIndex = this . rightChild ( treeIndex ) ;
40+ // 用户关注的区间和左孩子一点关系没有
41+ if ( queryL >= mid + 1 ) {
42+ // 去右子树查找
43+ return this . __query ( rightTreeIndex , mid + 1 , r , queryL , queryR ) ;
44+ }
45+ else if ( queryR <= mid ) {
46+ // 用户关注区间和右边没有关系
47+ return this . __query ( leftTreeIndex , l , mid , queryL , queryR ) ;
48+ }
49+ // 一部分左,一部分右 queryL R 被一份为二
50+ let leftResult = this . __query ( leftTreeIndex , l , mid , queryL , mid ) ;
51+ let rightResult = this . __query ( rightTreeIndex , mid + 1 , r , mid + 1 , queryR ) ;
52+ return this . merge ( leftResult , rightResult ) ;
53+ }
54+ // 遍历打印树中节点中值信息
55+ toString ( ) {
56+ let res = "[" ;
57+ for ( let i = 0 ; i < this . tree . length ; i ++ ) {
58+ if ( this . tree [ i ] !== undefined )
59+ res += this . tree [ i ] ;
60+ else
61+ res += "null" ;
62+
63+ if ( i != this . tree . length - 1 ) {
64+ res += ", " ;
65+ }
66+ }
67+ res += "]" ;
68+ return res ;
69+ }
70+ // 获得线段树的长度
71+ getSize ( ) {
72+ return this . data . length ;
73+ }
74+ // 获得索引所对应的值
75+ get ( index ) {
76+ return this . data [ index ] ;
77+ }
78+ // 线段树的更新操作
79+ // 将index位置的值,更新为e
80+ set ( index , e ) {
81+ this . data [ index ] = e ;
82+ this . __set ( 0 , 0 , this . data . length - 1 , index , e ) ;
83+ }
84+ // 在以treeIndex为根的线段树中更新index的值为e
85+ __set ( treeIndex , l , r , index , e ) {
86+ if ( l === r ) {
87+ this . tree [ treeIndex ] = e ;
88+ return ;
89+ }
90+ // 找到index所对应的叶子
91+ let mid = l + Math . floor ( ( r - l ) / 2 ) ;
92+ // 以treeIndex的节点为[l...mid]和[mid+1...r]两部分
93+ let leftTreeIndex = this . leftChild ( treeIndex ) ;
94+ let rightTreeIndex = this . rightChild ( treeIndex ) ;
95+ if ( index >= mid + 1 )
96+ this . __set ( rightTreeIndex , mid + 1 , r , index , e ) ;
97+ else // index <= mid
98+ this . __set ( leftTreeIndex , l , mid , index , e ) ;
99+ this . tree [ treeIndex ] = this . merge ( this . tree [ leftTreeIndex ] , this . tree [ rightTreeIndex ] ) ;
100+ }
101+ // 返回完全二叉树的数组表示中,一个索引所表示的元素的左孩子节点的索引
102+ leftChild ( index ) {
103+ return 2 * index + 1 ;
104+ }
105+ // 返回完全二叉树的数组表示中,一个索引所表示的元素的右孩子节点的索引
106+ rightChild ( index ) {
107+ return 2 * index + 2 ;
108+ }
109+ }
0 commit comments