diff options
Diffstat (limited to 'cli/js/rbtree.ts')
-rw-r--r-- | cli/js/rbtree.ts | 252 |
1 files changed, 0 insertions, 252 deletions
diff --git a/cli/js/rbtree.ts b/cli/js/rbtree.ts deleted file mode 100644 index fbade97b7..000000000 --- a/cli/js/rbtree.ts +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -// Derived from https://github.com/vadimg/js_bintrees. MIT Licensed. - -import { assert } from "./util.ts"; - -class RBNode<T> { - public left: this | null; - public right: this | null; - public red: boolean; - - constructor(public data: T) { - this.left = null; - this.right = null; - this.red = true; - } - - getChild(dir: boolean | number): this | null { - return dir ? this.right : this.left; - } - - setChild(dir: boolean | number, val: this | null): void { - if (dir) { - this.right = val; - } else { - this.left = val; - } - } -} - -export class RBTree<T> { - readonly #comparator: (a: T, b: T) => number; - #root: RBNode<T> | null; - - constructor(comparator: (a: T, b: T) => number) { - this.#comparator = comparator; - this.#root = null; - } - - /** Returns `null` if tree is empty. */ - min(): T | null { - let res = this.#root; - if (res === null) { - return null; - } - while (res.left !== null) { - res = res.left; - } - return res.data; - } - - /** Returns node `data` if found, `null` otherwise. */ - find(data: T): T | null { - let res = this.#root; - while (res !== null) { - const c = this.#comparator(data, res.data); - if (c === 0) { - return res.data; - } else { - res = res.getChild(c > 0); - } - } - return null; - } - - /** returns `true` if inserted, `false` if duplicate. */ - insert(data: T): boolean { - let ret = false; - - if (this.#root === null) { - // empty tree - this.#root = new RBNode(data); - ret = true; - } else { - const head = new RBNode((null as unknown) as T); // fake tree root - - let dir = 0; - let last = 0; - - // setup - let gp = null; // grandparent - let ggp = head; // grand-grand-parent - let p: RBNode<T> | null = null; // parent - let node: RBNode<T> | null = this.#root; - ggp.right = this.#root; - - // search down - while (true) { - if (node === null) { - // insert new node at the bottom - node = new RBNode(data); - p!.setChild(dir, node); - ret = true; - } else if (isRed(node.left) && isRed(node.right)) { - // color flip - node.red = true; - node.left!.red = false; - node.right!.red = false; - } - - // fix red violation - if (isRed(node) && isRed(p)) { - const dir2 = ggp.right === gp; - - assert(gp); - if (node === p!.getChild(last)) { - ggp.setChild(dir2, singleRotate(gp, !last)); - } else { - ggp.setChild(dir2, doubleRotate(gp, !last)); - } - } - - const cmp = this.#comparator(node.data, data); - - // stop if found - if (cmp === 0) { - break; - } - - last = dir; - dir = Number(cmp < 0); // Fix type - - // update helpers - if (gp !== null) { - ggp = gp; - } - gp = p; - p = node; - node = node.getChild(dir); - } - - // update root - this.#root = head.right; - } - - // make root black - this.#root!.red = false; - - return ret; - } - - /** Returns `true` if removed, `false` if not found. */ - remove(data: T): boolean { - if (this.#root === null) { - return false; - } - - const head = new RBNode((null as unknown) as T); // fake tree root - let node = head; - node.right = this.#root; - let p = null; // parent - let gp = null; // grand parent - let found = null; // found item - let dir: boolean | number = 1; - - while (node.getChild(dir) !== null) { - const last = dir; - - // update helpers - gp = p; - p = node; - node = node.getChild(dir)!; - - const cmp = this.#comparator(data, node.data); - - dir = cmp > 0; - - // save found node - if (cmp === 0) { - found = node; - } - - // push the red node down - if (!isRed(node) && !isRed(node.getChild(dir))) { - if (isRed(node.getChild(!dir))) { - const sr = singleRotate(node, dir); - p.setChild(last, sr); - p = sr; - } else if (!isRed(node.getChild(!dir))) { - const sibling = p.getChild(!last); - if (sibling !== null) { - if ( - !isRed(sibling.getChild(!last)) && - !isRed(sibling.getChild(last)) - ) { - // color flip - p.red = false; - sibling.red = true; - node.red = true; - } else { - assert(gp); - const dir2 = gp.right === p; - - if (isRed(sibling.getChild(last))) { - gp!.setChild(dir2, doubleRotate(p, last)); - } else if (isRed(sibling.getChild(!last))) { - gp!.setChild(dir2, singleRotate(p, last)); - } - - // ensure correct coloring - const gpc = gp.getChild(dir2); - assert(gpc); - gpc.red = true; - node.red = true; - assert(gpc.left); - gpc.left.red = false; - assert(gpc.right); - gpc.right.red = false; - } - } - } - } - } - - // replace and remove if found - if (found !== null) { - found.data = node.data; - assert(p); - p.setChild(p.right === node, node.getChild(node.left === null)); - } - - // update root and make it black - this.#root = head.right; - if (this.#root !== null) { - this.#root.red = false; - } - - return found !== null; - } -} - -function isRed<T>(node: RBNode<T> | null): boolean { - return node !== null && node.red; -} - -function singleRotate<T>(root: RBNode<T>, dir: boolean | number): RBNode<T> { - const save = root.getChild(!dir); - assert(save); - - root.setChild(!dir, save.getChild(dir)); - save.setChild(dir, root); - - root.red = true; - save.red = false; - - return save; -} - -function doubleRotate<T>(root: RBNode<T>, dir: boolean | number): RBNode<T> { - root.setChild(!dir, singleRotate(root.getChild(!dir)!, !dir)); - return singleRotate(root, dir); -} |