UNPKG

sonic-forest

Version:

High-performance (binary) tree and sorted map implementation (AVL, Splay, Radix, Red-Black)

621 lines (620 loc) 21.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SortedMap = void 0; const printTree_1 = require("../print/printTree"); const SortedMapIterator_1 = require("./SortedMapIterator"); const SortedMapNode_1 = require("./SortedMapNode"); const SortedMapNode_2 = require("./SortedMapNode"); const util_1 = require("./util"); const util_2 = require("../util"); const print_1 = require("../red-black/util/print"); class SortedMap { constructor(comparator, enableIndex = false) { this._root = undefined; this._length = 0; this.min = undefined; this.root = undefined; this.max = undefined; this._size = 0; this.next = util_2.next; this.comparator = comparator || ((a, b) => (a === b ? 0 : a < b ? -1 : 1)); this.enableIndex = enableIndex; this._TreeNodeClass = enableIndex ? SortedMapNode_2.TreeNodeEnableIndex : SortedMapNode_1.TreeNode; this._header = new this._TreeNodeClass(undefined, undefined); } get length() { return this._length; } empty() { return this._length === 0; } _lowerBound(curNode, key) { let resNode = this._header; while (curNode) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult < 0) { curNode = curNode.r; } else if (cmpResult > 0) { resNode = curNode; curNode = curNode.l; } else return curNode; } return resNode; } _upperBound(curNode, key) { let resNode = this._header; while (curNode) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult <= 0) { curNode = curNode.r; } else { resNode = curNode; curNode = curNode.l; } } return resNode; } _reverseLowerBound(curNode, key) { let resNode = this._header; while (curNode) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult < 0) { resNode = curNode; curNode = curNode.r; } else if (cmpResult > 0) { curNode = curNode.l; } else return curNode; } return resNode; } _reverseUpperBound(curNode, key) { let resNode = this._header; while (curNode) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult < 0) { resNode = curNode; curNode = curNode.r; } else { curNode = curNode.l; } } return resNode; } _eraseNodeSelfBalance(curNode) { while (true) { const parentNode = curNode.p; if (parentNode === this._header) return; if (!curNode.b) { curNode.b = true; return; } if (curNode === parentNode.l) { const brother = parentNode.r; if (!brother.b) { brother.b = true; parentNode.b = false; if (parentNode === this._root) { this._root = parentNode.rRotate(); } else parentNode.rRotate(); } else { if (brother.r && brother.r.b === false) { brother.b = parentNode.b; parentNode.b = true; brother.r.b = true; if (parentNode === this._root) { this._root = parentNode.rRotate(); } else parentNode.rRotate(); return; } else if (brother.l && brother.l.b === false) { brother.b = false; brother.l.b = true; brother.lRotate(); } else { brother.b = false; curNode = parentNode; } } } else { const brother = parentNode.l; if (brother.b === false) { brother.b = true; parentNode.b = false; if (parentNode === this._root) { this._root = parentNode.lRotate(); } else parentNode.lRotate(); } else { if (brother.l && brother.l.b === false) { brother.b = parentNode.b; parentNode.b = true; brother.l.b = true; if (parentNode === this._root) { this._root = parentNode.lRotate(); } else parentNode.lRotate(); return; } else if (brother.r && brother.r.b === false) { brother.b = false; brother.r.b = true; brother.rRotate(); } else { brother.b = false; curNode = parentNode; } } } } } _eraseNode(curNode) { if (this._length === 1) { this.clear(); return; } let swapNode = curNode; while (swapNode.l || swapNode.r) { if (swapNode.r) { swapNode = swapNode.r; while (swapNode.l) swapNode = swapNode.l; } else { swapNode = swapNode.l; } const key = curNode.k; curNode.k = swapNode.k; swapNode.k = key; const value = curNode.v; curNode.v = swapNode.v; swapNode.v = value; curNode = swapNode; } if (this._header.l === swapNode) { this._header.l = swapNode.p; } else if (this._header.r === swapNode) { this._header.r = swapNode.p; } this._eraseNodeSelfBalance(swapNode); let _parent = swapNode.p; if (swapNode === _parent.l) { _parent.l = undefined; } else _parent.r = undefined; this._length -= 1; this._root.b = true; if (this.enableIndex) { while (_parent !== this._header) { _parent._size -= 1; _parent = _parent.p; } } } _insertNodeSelfBalance(curNode) { while (true) { const parentNode = curNode.p; if (parentNode.b === true) return; const grandParent = parentNode.p; if (parentNode === grandParent.l) { const uncle = grandParent.r; if (uncle && uncle.b === false) { uncle.b = parentNode.b = true; if (grandParent === this._root) return; grandParent.b = false; curNode = grandParent; continue; } else if (curNode === parentNode.r) { curNode.b = true; if (curNode.l) { curNode.l.p = parentNode; } if (curNode.r) { curNode.r.p = grandParent; } parentNode.r = curNode.l; grandParent.l = curNode.r; curNode.l = parentNode; curNode.r = grandParent; if (grandParent === this._root) { this._root = curNode; this._header.p = curNode; } else { const GP = grandParent.p; if (GP.l === grandParent) { GP.l = curNode; } else GP.r = curNode; } curNode.p = grandParent.p; parentNode.p = curNode; grandParent.p = curNode; grandParent.b = false; } else { parentNode.b = true; if (grandParent === this._root) { this._root = grandParent.lRotate(); } else grandParent.lRotate(); grandParent.b = false; return; } } else { const uncle = grandParent.l; if (uncle && uncle.b === false) { uncle.b = parentNode.b = true; if (grandParent === this._root) return; grandParent.b = false; curNode = grandParent; continue; } else if (curNode === parentNode.l) { curNode.b = true; if (curNode.l) { curNode.l.p = grandParent; } if (curNode.r) { curNode.r.p = parentNode; } grandParent.r = curNode.l; parentNode.l = curNode.r; curNode.l = grandParent; curNode.r = parentNode; if (grandParent === this._root) { this._root = curNode; this._header.p = curNode; } else { const GP = grandParent.p; if (GP.l === grandParent) { GP.l = curNode; } else GP.r = curNode; } curNode.p = grandParent.p; parentNode.p = curNode; grandParent.p = curNode; grandParent.b = false; } else { parentNode.b = true; if (grandParent === this._root) { this._root = grandParent.rRotate(); } else grandParent.rRotate(); grandParent.b = false; return; } } if (this.enableIndex) { parentNode.compute(); grandParent.compute(); curNode.compute(); } return; } } _set(key, value, hint) { if (this._root === undefined) { this._length += 1; this._root = new this._TreeNodeClass(key, value, true); this._root.p = this._header; this._header.p = this._header.l = this._header.r = this._root; return this._length; } let curNode; const minNode = this._header.l; const compareToMin = this.comparator(minNode.k, key); if (compareToMin === 0) { minNode.v = value; return this._length; } else if (compareToMin > 0) { minNode.l = new this._TreeNodeClass(key, value); minNode.l.p = minNode; curNode = minNode.l; this._header.l = curNode; } else { const maxNode = this._header.r; const compareToMax = this.comparator(maxNode.k, key); if (compareToMax === 0) { maxNode.v = value; return this._length; } else if (compareToMax < 0) { maxNode.r = new this._TreeNodeClass(key, value); maxNode.r.p = maxNode; curNode = maxNode.r; this._header.r = curNode; } else { if (hint !== undefined) { const iterNode = hint._node; if (iterNode !== this._header) { const iterCmpRes = this.comparator(iterNode.k, key); if (iterCmpRes === 0) { iterNode.v = value; return this._length; } else if (iterCmpRes > 0) { const preNode = iterNode.prev(); const preCmpRes = this.comparator(preNode.k, key); if (preCmpRes === 0) { preNode.v = value; return this._length; } else if (preCmpRes < 0) { curNode = new this._TreeNodeClass(key, value); if (preNode.r === undefined) { preNode.r = curNode; curNode.p = preNode; } else { iterNode.l = curNode; curNode.p = iterNode; } } } } } if (curNode === undefined) { curNode = this._root; while (true) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult > 0) { if (curNode.l === undefined) { curNode.l = new this._TreeNodeClass(key, value); curNode.l.p = curNode; curNode = curNode.l; break; } curNode = curNode.l; } else if (cmpResult < 0) { if (curNode.r === undefined) { curNode.r = new this._TreeNodeClass(key, value); curNode.r.p = curNode; curNode = curNode.r; break; } curNode = curNode.r; } else { curNode.v = value; return this._length; } } } } } if (this.enableIndex) { let parent = curNode.p; while (parent !== this._header) { parent._size += 1; parent = parent.p; } } this._insertNodeSelfBalance(curNode); this._length += 1; return this._length; } _getTreeNodeByKey(curNode, key) { while (curNode) { const cmpResult = this.comparator(curNode.k, key); if (cmpResult < 0) { curNode = curNode.r; } else if (cmpResult > 0) { curNode = curNode.l; } else return curNode; } return curNode || this._header; } updateKeyByIterator(iter, key) { const node = iter._node; if (node === this._header) { (0, util_1.throwIteratorAccessError)(); } if (this._length === 1) { node.k = key; return true; } const nextKey = node.next().k; if (node === this._header.l) { if (this.comparator(nextKey, key) > 0) { node.k = key; return true; } return false; } const preKey = node.prev().k; if (node === this._header.r) { if (this.comparator(preKey, key) < 0) { node.k = key; return true; } return false; } if (this.comparator(preKey, key) >= 0 || this.comparator(nextKey, key) <= 0) return false; node.k = key; return true; } eraseElementByPos(pos) { throw new Error('Method not implemented.'); } eraseElementByKey(key) { if (this._length === 0) return false; const curNode = this._getTreeNodeByKey(this._root, key); if (curNode === this._header) return false; this._eraseNode(curNode); return true; } eraseElementByIterator(iter) { const node = iter._node; if (node === this._header) { (0, util_1.throwIteratorAccessError)(); } const hasNoRight = node.r === undefined; const isNormal = iter.iteratorType === 0; if (isNormal) { if (hasNoRight) iter.next(); } else { if (!hasNoRight || node.l === undefined) iter.next(); } this._eraseNode(node); return iter; } getHeight() { if (this._length === 0) return 0; function traversal(curNode) { if (!curNode) return 0; return Math.max(traversal(curNode.l), traversal(curNode.r)) + 1; } return traversal(this._root); } begin() { return new SortedMapIterator_1.OrderedMapIterator(this._header.l || this._header, this._header, this); } end() { return new SortedMapIterator_1.OrderedMapIterator(this._header, this._header, this); } rBegin() { return new SortedMapIterator_1.OrderedMapIterator(this._header.r || this._header, this._header, this, 1); } rEnd() { return new SortedMapIterator_1.OrderedMapIterator(this._header, this._header, this, 1); } front() { if (this._length === 0) return; const minNode = this._header.l; return [minNode.k, minNode.v]; } back() { if (this._length === 0) return; const maxNode = this._header.r; return [maxNode.k, maxNode.v]; } lowerBound(key) { const resNode = this._lowerBound(this._root, key); return new SortedMapIterator_1.OrderedMapIterator(resNode, this._header, this); } upperBound(key) { const resNode = this._upperBound(this._root, key); return new SortedMapIterator_1.OrderedMapIterator(resNode, this._header, this); } reverseLowerBound(key) { const resNode = this._reverseLowerBound(this._root, key); return new SortedMapIterator_1.OrderedMapIterator(resNode, this._header, this); } reverseUpperBound(key) { const resNode = this._reverseUpperBound(this._root, key); return new SortedMapIterator_1.OrderedMapIterator(resNode, this._header, this); } setElement(key, value, hint) { return this._set(key, value, hint); } getElementByPos(pos) { throw new Error('Method not implemented.'); } getElementByKey(key) { const curNode = this._getTreeNodeByKey(this._root, key); return curNode.v; } set(k, v) { throw new Error('Method not implemented.'); } find(k) { throw new Error('Method not implemented.'); } get(k) { throw new Error('Method not implemented.'); } del(k) { throw new Error('Method not implemented.'); } clear() { this._length = 0; this._root = undefined; this._header.p = undefined; this._header.l = this._header.r = undefined; } has(k) { return !!this.find(k); } size() { return this._length; } isEmpty() { return !this.min; } getOrNextLower(k) { throw new Error('Method not implemented.'); } forEach(fn) { throw new Error('Method not implemented.'); } first() { throw new Error('Method not implemented.'); } last() { throw new Error('Method not implemented.'); } iterator0() { throw new Error('Method not implemented.'); } iterator() { throw new Error('Method not implemented.'); } entries() { throw new Error('Method not implemented.'); } toString(tab) { return this.constructor.name + (0, printTree_1.printTree)(tab, [(tab) => (0, print_1.print)(this.root, tab)]); } } exports.SortedMap = SortedMap;