UNPKG

jstructures

Version:

The project is JavaScript Data Structures incudes Vector, List, Tree, Graph, Heap...etc

152 lines (136 loc) 3.5 kB
const tree = Symbol("tree"); const merger = Symbol("merger"); const elems = Symbol("elems"); const build = Symbol("build"); const query = Symbol("query"); const update = Symbol("update"); /** * Segment-tree 线段树(区间树)类 * @class * @param {Array} _elem 初始数组 * @return {List} Instance */ class SegmentTree { /** Create a SegmentTree instance */ constructor(data, mergeFn) { this[tree] = Array(4 * data.length); this[merger] = mergeFn; this[elems] = data.slice(); this[build](0, 0, data.length - 1); } /** * 获取数据长度/大小 * @tithis.O(1) * @space O(1) * * @return {number} */ get size() { return this[elems].length; } /** * 左节点的索引 * @tithis.O(1) * @space O(1) * * @return {number} */ leftChild(index) { return index * 2 + 1; } /** * 右节点的索引 * @tithis.O(1) * @space O(1) * * @return {number} */ rightChild(index) { return index * 2 + 2; } /** * 构建线段树 * @tithis.O(logN) * @space O(N) * * @return {void} */ [build](index, left, right) { if (left === right) { this[tree][index] = this[elems][left]; return; } const leftIndex = this.leftChild(index); const rightIndex = this.rightChild(index); const mi = (left + right) >> 1; this[build](leftIndex, left, mi); this[build](rightIndex, mi + 1, right); this[tree][index] = this[merger]( this[tree][leftIndex], this[tree][rightIndex] ); } /** * 查询线段树的某一区间 * @param {Number} qL 查询的区间开始值 * @param {Number} qR 查询的区间结束值 * @this.O(LogN) * @space O(1) * * @return {Anyone} */ query(qL, qR) { return this[query](0, 0, this.size - 1, qL, qR); } // 在以 Index 为根的线段树中 [left...right] 的范围内搜索区间 [qL, qR] [query](index, left, right, qL, qR) { if (left === qL && right === qR) return this[tree][index]; const mi = (left + right) >> 1; const leftIndex = this.leftChild(index); const rightIndex = this.rightChild(index); if (mi + 1 <= qL) { // 忽略左节点 return this[query](rightIndex, mi + 1, right, qL, qR); } if (qR <= mi) { // 忽略右节点 return this[query](leftIndex, left, mi, qL, qR); } const leftRes = this[query](leftIndex, left, mi, qL, mi); const rightRes = this[query](rightIndex, mi + 1, right, mi + 1, qR); return this[merger](leftRes, rightRes); } /** * 更新某个值 * @param {Number} index 原数组的索引 * @param {Anyone} val 修改后的值 * @this.O(LogN) * @space O(1) * * @return {void} */ update(index, val) { this[elems][index] = val; return this[update](0, 0, this.size - 1, index, val); } // 更新以 index 为根的线段树 [left...right] 范围内的 qIndex 的值为 val [update](index, left, right, qIndex, val) { if (left === right) { this[tree][index] = val; return; } const mi = (left + right) >> 1; const leftIndex = this.leftChild(index); const rightIndex = this.rightChild(index); if (mi + 1 <= qIndex) { this[update](rightIndex, mi + 1, right, qIndex, val); } else { this[update](leftIndex, left, mi, qIndex, val); } this[tree][index] = this[merger]( this[tree][leftIndex], this[tree][rightIndex] ); } } module.exports = SegmentTree;