sonic-forest
Version:
High-performance (binary) tree and sorted map implementation (AVL, Splay, Radix, Red-Black)
621 lines (620 loc) • 21.2 kB
JavaScript
"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;