Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions collections/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -943,15 +943,15 @@ assertEquals([...words], ["truck", "tank", "car"]);
assertEquals([...words], []);
```

### BSTree
### BinarySearchTree

An unbalanced binary search tree. The values are in ascending order by default,
using JavaScript's built in comparison operators to sort the values.

For performance, it's recommended that you use a self balancing binary search
tree instead of this one unless you are extending this to create a self
balancing tree. See RBTree for an example of how BSTree can be extended to
create a self balancing binary search tree.
balancing tree. See RedBlackTree for an example of how BinarySearchTree can be
extended to create a self balancing binary search tree.

| Method | Average Case | Worst Case |
| ------------- | ------------ | ---------- |
Expand All @@ -964,13 +964,13 @@ create a self balancing binary search tree.
```ts
import {
ascend,
BSTree,
BinarySearchTree,
descend,
} from "https://deno.land/std@$STD_VERSION/collections/bs_tree.ts";
} from "https://deno.land/std@$STD_VERSION/collections/binary_search_tree.ts";
import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";

const values = [3, 10, 13, 4, 6, 7, 1, 14];
const tree = new BSTree<number>();
const tree = new BinarySearchTree<number>();
values.forEach((value) => tree.insert(value));
assertEquals([...tree], [1, 3, 4, 6, 7, 10, 13, 14]);
assertEquals(tree.min(), 1);
Expand All @@ -981,7 +981,7 @@ assertEquals(tree.remove(42), false);
assertEquals(tree.remove(7), true);
assertEquals([...tree], [1, 3, 4, 6, 10, 13, 14]);

const invertedTree = new BSTree<number>(descend);
const invertedTree = new BinarySearchTree<number>(descend);
values.forEach((value) => invertedTree.insert(value));
assertEquals([...invertedTree], [14, 13, 10, 7, 6, 4, 3, 1]);
assertEquals(invertedTree.min(), 14);
Expand All @@ -992,7 +992,7 @@ assertEquals(invertedTree.remove(42), false);
assertEquals(invertedTree.remove(7), true);
assertEquals([...invertedTree], [14, 13, 10, 6, 4, 3, 1]);

const words = new BSTree<string>((a, b) =>
const words = new BinarySearchTree<string>((a, b) =>
ascend(a.length, b.length) || ascend(a, b)
);
["truck", "car", "helicopter", "tank", "train", "suv", "semi", "van"]
Expand Down Expand Up @@ -1024,7 +1024,7 @@ assertEquals([...words], [
]);
```

### RBTree
### RedBlackTree

A red-black tree. This is a kind of self-balancing binary search tree. The
values are in ascending order by default, using JavaScript's built in comparison
Expand All @@ -1047,12 +1047,12 @@ Trees, so they can provide faster lookups.
import {
ascend,
descend,
RBTree,
} from "https://deno.land/std@$STD_VERSION/collections/rb_tree.ts";
RedBlackTree,
} from "https://deno.land/std@$STD_VERSION/collections/red_black_tree.ts";
import { assertEquals } from "https://deno.land/std@$STD_VERSION/testing/asserts.ts";

const values = [3, 10, 13, 4, 6, 7, 1, 14];
const tree = new RBTree<number>();
const tree = new RedBlackTree<number>();
values.forEach((value) => tree.insert(value));
assertEquals([...tree], [1, 3, 4, 6, 7, 10, 13, 14]);
assertEquals(tree.min(), 1);
Expand All @@ -1063,7 +1063,7 @@ assertEquals(tree.remove(42), false);
assertEquals(tree.remove(7), true);
assertEquals([...tree], [1, 3, 4, 6, 10, 13, 14]);

const invertedTree = new RBTree<number>(descend);
const invertedTree = new RedBlackTree<number>(descend);
values.forEach((value) => invertedTree.insert(value));
assertEquals([...invertedTree], [14, 13, 10, 7, 6, 4, 3, 1]);
assertEquals(invertedTree.min(), 14);
Expand All @@ -1074,7 +1074,7 @@ assertEquals(invertedTree.remove(42), false);
assertEquals(invertedTree.remove(7), true);
assertEquals([...invertedTree], [14, 13, 10, 6, 4, 3, 1]);

const words = new RBTree<string>((a, b) =>
const words = new RedBlackTree<string>((a, b) =>
ascend(a.length, b.length) || ascend(a, b)
);
["truck", "car", "helicopter", "tank", "train", "suv", "semi", "van"]
Expand Down
56 changes: 56 additions & 0 deletions collections/binary_search_node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
/** This module is browser compatible. */

export type Direction = "left" | "right";

export class BinarySearchNode<T> {
left: BinarySearchNode<T> | null;
right: BinarySearchNode<T> | null;
constructor(public parent: BinarySearchNode<T> | null, public value: T) {
this.left = null;
this.right = null;
}

static from<T>(node: BinarySearchNode<T>): BinarySearchNode<T> {
const copy: BinarySearchNode<T> = new BinarySearchNode(
node.parent,
node.value,
);
copy.left = node.left;
copy.right = node.right;
return copy;
}

directionFromParent(): Direction | null {
return this.parent === null
? null
: this === this.parent.left
? "left"
: this === this.parent.right
? "right"
: null;
}

findMinNode(): BinarySearchNode<T> {
let minNode: BinarySearchNode<T> | null = this.left;
while (minNode?.left) minNode = minNode.left;
return minNode ?? this;
}

findMaxNode(): BinarySearchNode<T> {
let maxNode: BinarySearchNode<T> | null = this.right;
while (maxNode?.right) maxNode = maxNode.right;
return maxNode ?? this;
}

findSuccessorNode(): BinarySearchNode<T> | null {
if (this.right !== null) return this.right.findMinNode();
let parent: BinarySearchNode<T> | null = this.parent;
let direction: Direction | null = this.directionFromParent();
while (parent && direction === "right") {
direction = parent.directionFromParent();
parent = parent.parent;
}
return parent;
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertStrictEquals } from "../testing/asserts.ts";
import { BSNode } from "./bs_node.ts";
import { BinarySearchNode } from "./binary_search_node.ts";

let parent: BSNode<number>;
let child: BSNode<number>;
let parent: BinarySearchNode<number>;
let child: BinarySearchNode<number>;
function beforeEach() {
parent = new BSNode(null, 5);
child = new BSNode(parent, 7);
parent = new BinarySearchNode(null, 5);
child = new BinarySearchNode(parent, 7);
parent.right = child;
}

Deno.test("[collections/BSNode] constructor", () => {
Deno.test("[collections/BinarySearchNode] constructor", () => {
beforeEach();
assertStrictEquals(parent.parent, null);
assertStrictEquals(parent.left, null);
Expand All @@ -23,10 +23,10 @@ Deno.test("[collections/BSNode] constructor", () => {
assertStrictEquals(child.value, 7);
});

Deno.test("[collections/BSNode] from", () => {
Deno.test("[collections/BinarySearchNode] from", () => {
beforeEach();
const parentClone: BSNode<number> = BSNode.from(parent);
const childClone: BSNode<number> = BSNode.from(child);
const parentClone: BinarySearchNode<number> = BinarySearchNode.from(parent);
const childClone: BinarySearchNode<number> = BinarySearchNode.from(child);

assertStrictEquals(parentClone.parent, null);
assertStrictEquals(parentClone.left, null);
Expand All @@ -39,51 +39,51 @@ Deno.test("[collections/BSNode] from", () => {
assertStrictEquals(childClone.value, 7);
});

Deno.test("[collections/BSNode] directionFromParent", () => {
Deno.test("[collections/BinarySearchNode] directionFromParent", () => {
beforeEach();
const child2 = new BSNode(parent, 3);
const child2 = new BinarySearchNode(parent, 3);
assertEquals(child2.directionFromParent(), null);
parent.left = child2;
assertEquals(child2.directionFromParent(), "left");
assertEquals(parent.directionFromParent(), null);
assertEquals(child.directionFromParent(), "right");
});

Deno.test("[collections/BSNode] findMinNode", () => {
Deno.test("[collections/BinarySearchNode] findMinNode", () => {
beforeEach();
assertStrictEquals(parent.findMinNode(), parent);
const child2 = new BSNode(parent, 3);
const child2 = new BinarySearchNode(parent, 3);
parent.left = child2;
assertStrictEquals(parent.findMinNode(), child2);
const child3 = new BSNode(child2, 4);
const child3 = new BinarySearchNode(child2, 4);
child2.right = child3;
assertStrictEquals(parent.findMinNode(), child2);
const child4 = new BSNode(child2, 2);
const child4 = new BinarySearchNode(child2, 2);
child2.left = child4;
assertStrictEquals(parent.findMinNode(), child4);
});

Deno.test("[collections/BSNode] findMaxNode", () => {
Deno.test("[collections/BinarySearchNode] findMaxNode", () => {
beforeEach();
assertStrictEquals(parent.findMaxNode(), child);
const child2 = new BSNode(child, 6);
const child2 = new BinarySearchNode(child, 6);
child.left = child2;
assertStrictEquals(parent.findMaxNode(), child);
const child3 = new BSNode(child2, 6.5);
const child3 = new BinarySearchNode(child2, 6.5);
child2.right = child3;
assertStrictEquals(parent.findMaxNode(), child);
const child4 = new BSNode(child2, 8);
const child4 = new BinarySearchNode(child2, 8);
child.right = child4;
assertStrictEquals(parent.findMaxNode(), child4);
parent.right = null;
assertStrictEquals(parent.findMaxNode(), parent);
});

Deno.test("[collections/BSNode] findSuccessorNode", () => {
Deno.test("[collections/BinarySearchNode] findSuccessorNode", () => {
beforeEach();
assertStrictEquals(parent.findSuccessorNode(), child);
assertStrictEquals(child.findSuccessorNode(), null);
const child2 = new BSNode(child, 6);
const child2 = new BinarySearchNode(child, 6);
child.left = child2;
assertStrictEquals(parent.findSuccessorNode(), child2);
assertStrictEquals(child.findSuccessorNode(), null);
Expand Down
Loading