Skip to main content
Using Deno in production at your company? Earn free Deno merch.
Give us feedback
Go to Latest
File
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.import { assert, assertEquals, assertStrictEquals, assertThrows,} from "../assert/mod.ts";import { BinarySearchTree } from "./binary_search_tree.ts";import { ascend, descend } from "./comparators.ts";
class MyMath { multiply(a: number, b: number): number { return a * b; }}
interface Container { id: number; values: number[];}
Deno.test("BinarySearchTree handles default ascend comparator", () => { const trees = [ new BinarySearchTree(), new BinarySearchTree(), ] as const; const values: number[] = [-10, 9, -1, 100, 1, 0, -100, 10, -9];
const expectedMin: number[][] = [ [-10, -10, -10, -10, -10, -10, -100, -100, -100], [-9, -9, -100, -100, -100, -100, -100, -100, -100], ]; const expectedMax: number[][] = [ [-10, 9, 9, 100, 100, 100, 100, 100, 100], [-9, 10, 10, 10, 10, 100, 100, 100, 100], ]; for (const [i, tree] of trees.entries()) { assertEquals(tree.size, 0); assertEquals(tree.isEmpty(), true); for (const [j, value] of values.entries()) { assertEquals(tree.find(value), null); assertEquals(tree.insert(value), true); assertEquals(tree.find(value), value); assertEquals(tree.size, j + 1); assertEquals(tree.isEmpty(), false); assertEquals(tree.min(), expectedMin?.[i]?.[j]); assertEquals(tree.max(), expectedMax?.[i]?.[j]); } for (const value of values) { assertEquals(tree.insert(value), false); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); assertEquals(tree.min(), -100); assertEquals(tree.max(), 100); } values.reverse(); }
for (const tree of trees) { assertEquals( [...tree.lnrValues()], [-100, -10, -9, -1, 0, 1, 9, 10, 100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false);
assertEquals( [...tree], [-100, -10, -9, -1, 0, 1, 9, 10, 100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false);
assertEquals( [...tree.rnlValues()], [100, 10, 9, 1, 0, -1, -9, -10, -100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].nlrValues()], [-10, -100, 9, -1, -9, 1, 0, 100, 10], ); assertEquals( [...trees[1].nlrValues()], [-9, -100, -10, 10, 0, -1, 1, 9, 100], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].lrnValues()], [-100, -9, 0, 1, -1, 10, 100, 9, -10], ); assertEquals( [...trees[1].lrnValues()], [-10, -100, -1, 9, 1, 0, 100, 10, -9], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].lvlValues()], [-10, -100, 9, -1, 100, -9, 1, 10, 0], ); assertEquals( [...trees[1].lvlValues()], [-9, -100, 10, -10, 0, 100, -1, 1, 9], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
for (const tree of trees) { const expected: number[] = [-100, -10, -9, -1, 0, 1, 9, 10, 100]; for (const [j, value] of values.entries()) { assertEquals(tree.size, values.length - j); assertEquals(tree.isEmpty(), false); assertEquals(tree.find(value), value);
assertEquals(tree.remove(value), true); expected.splice(expected.indexOf(value), 1); assertEquals([...tree], expected); assertEquals(tree.find(value), null);
assertEquals(tree.remove(value), false); assertEquals([...tree], expected); assertEquals(tree.find(value), null); } assertEquals(tree.size, 0); assertEquals(tree.isEmpty(), true); }});
Deno.test("BinarySearchTree handles descend comparator", () => { const trees = [ new BinarySearchTree(descend), new BinarySearchTree(descend), ] as const; const values: number[] = [-10, 9, -1, 100, 1, 0, -100, 10, -9];
const expectedMin: number[][] = [ [-10, 9, 9, 100, 100, 100, 100, 100, 100], [-9, 10, 10, 10, 10, 100, 100, 100, 100, 100], ]; const expectedMax: number[][] = [ [-10, -10, -10, -10, -10, -10, -100, -100, -100], [-9, -9, -100, -100, -100, -100, -100, -100, -100], ]; for (const [i, tree] of trees.entries()) { assertEquals(tree.size, 0); assertEquals(tree.isEmpty(), true); for (const [j, value] of values.entries()) { assertEquals(tree.find(value), null); assertEquals(tree.insert(value), true); assertEquals(tree.find(value), value); assertEquals(tree.size, j + 1); assertEquals(tree.isEmpty(), false); assertEquals(tree.min(), expectedMin?.[i]?.[j]); assertEquals(tree.max(), expectedMax?.[i]?.[j]); } for (const value of values) { assertEquals(tree.insert(value), false); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); assertEquals(tree.min(), 100); assertEquals(tree.max(), -100); } values.reverse(); }
for (const tree of trees) { assertEquals( [...tree.lnrValues()], [100, 10, 9, 1, 0, -1, -9, -10, -100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false);
assertEquals( [...tree], [100, 10, 9, 1, 0, -1, -9, -10, -100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false);
assertEquals( [...tree.rnlValues()], [-100, -10, -9, -1, 0, 1, 9, 10, 100], ); assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].nlrValues()], [-10, 9, 100, 10, -1, 1, 0, -9, -100], ); assertEquals( [...trees[1].nlrValues()], [-9, 10, 100, 0, 1, 9, -1, -100, -10], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].lrnValues()], [10, 100, 0, 1, -9, -1, 9, -100, -10], ); assertEquals( [...trees[1].lrnValues()], [100, 9, 1, -1, 0, 10, -10, -100, -9], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...trees[0].lvlValues()], [-10, 9, -100, 100, -1, 10, 1, -9, 0], ); assertEquals( [...trees[1].lvlValues()], [-9, 10, -100, 100, 0, -10, 1, -1, 9], ); for (const tree of trees) { assertEquals(tree.size, values.length); assertEquals(tree.isEmpty(), false); }
for (const tree of trees) { const expected: number[] = [100, 10, 9, 1, 0, -1, -9, -10, -100]; for (const [j, value] of values.entries()) { assertEquals(tree.size, values.length - j); assertEquals(tree.isEmpty(), false); assertEquals(tree.find(value), value);
assertEquals(tree.remove(value), true); expected.splice(expected.indexOf(value), 1); assertEquals([...tree], expected); assertEquals(tree.find(value), null);
assertEquals(tree.remove(value), false); assertEquals([...tree], expected); assertEquals(tree.find(value), null); } assertEquals(tree.size, 0); assertEquals(tree.isEmpty(), true); }});
Deno.test("BinarySearchTree contains objects", () => { const tree: BinarySearchTree<Container> = new BinarySearchTree(( a: Container, b: Container, ) => ascend(a.id, b.id)); const ids = [-10, 9, -1, 100, 1, 0, -100, 10, -9];
for (const [i, id] of ids.entries()) { const newContainer: Container = { id, values: [] }; assertEquals(tree.find(newContainer), null); assertEquals(tree.insert(newContainer), true); newContainer.values.push(i - 1, i, i + 1); assertStrictEquals(tree.find({ id, values: [] }), newContainer); assertEquals(tree.size, i + 1); assertEquals(tree.isEmpty(), false); } for (const [i, id] of ids.entries()) { const newContainer: Container = { id, values: [] }; assertEquals( tree.find({ id } as Container), { id, values: [i - 1, i, i + 1] }, ); assertEquals(tree.insert(newContainer), false); assertEquals( tree.find({ id, values: [] }), { id, values: [i - 1, i, i + 1] }, ); assertEquals(tree.size, ids.length); assertEquals(tree.isEmpty(), false); }
assertEquals( [...tree].map((container) => container.id), [-100, -10, -9, -1, 0, 1, 9, 10, 100], ); assertEquals(tree.size, ids.length); assertEquals(tree.isEmpty(), false);
const expected: number[] = [-100, -10, -9, -1, 0, 1, 9, 10, 100]; for (const [i, id] of ids.entries()) { assertEquals(tree.size, ids.length - i); assertEquals(tree.isEmpty(), false); assertEquals( tree.find({ id, values: [] }), { id, values: [i - 1, i, i + 1] }, );
assertEquals(tree.remove({ id, values: [] }), true); expected.splice(expected.indexOf(id), 1); assertEquals([...tree].map((container) => container.id), expected); assertEquals(tree.find({ id, values: [] }), null);
assertEquals(tree.remove({ id, values: [] }), false); assertEquals([...tree].map((container) => container.id), expected); assertEquals(tree.find({ id, values: [] }), null); } assertEquals(tree.size, 0); assertEquals(tree.isEmpty(), true);});
Deno.test("BinarySearchTree.from() handles iterable", () => { const values: number[] = [-10, 9, -1, 100, 9, 1, 0, 9, -100, 10, -9]; const originalValues: number[] = Array.from(values); const expected: number[] = [-100, -10, -9, -1, 0, 1, 9, 10, 100]; let tree: BinarySearchTree<number> = BinarySearchTree.from(values); assertEquals(values, originalValues); assertEquals([...tree], expected); assertEquals([...tree.nlrValues()], [-10, -100, 9, -1, -9, 1, 0, 100, 10]); assertEquals([...tree.lvlValues()], [-10, -100, 9, -1, 100, -9, 1, 10, 0]);
tree = BinarySearchTree.from(values, { compare: descend }); assertEquals(values, originalValues); assertEquals([...tree].reverse(), expected); assertEquals([...tree.nlrValues()], [-10, 9, 100, 10, -1, 1, 0, -9, -100]); assertEquals([...tree.lvlValues()], [-10, 9, -100, 100, -1, 10, 1, -9, 0]);
tree = BinarySearchTree.from(values, { map: (v: number) => 2 * v, }); assertEquals([...tree], expected.map((v: number) => 2 * v)); assertEquals([...tree.nlrValues()], [-20, -200, 18, -2, -18, 2, 0, 200, 20]); assertEquals([...tree.lvlValues()], [-20, -200, 18, -2, 200, -18, 2, 20, 0]);
const math = new MyMath(); tree = BinarySearchTree.from(values, { map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals(values, originalValues); assertEquals([...tree], expected.map((v: number) => 3 * v)); assertEquals([...tree.nlrValues()], [-30, -300, 27, -3, -27, 3, 0, 300, 30]); assertEquals([...tree.lvlValues()], [-30, -300, 27, -3, 300, -27, 3, 30, 0]);
tree = BinarySearchTree.from(values, { compare: descend, map: (v: number) => 2 * v, }); assertEquals(values, originalValues); assertEquals([...tree].reverse(), expected.map((v: number) => 2 * v)); assertEquals([...tree.nlrValues()], [-20, 18, 200, 20, -2, 2, 0, -18, -200]); assertEquals([...tree.lvlValues()], [-20, 18, -200, 200, -2, 20, 2, -18, 0]);
tree = BinarySearchTree.from(values, { compare: descend, map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals(values, originalValues); assertEquals([...tree].reverse(), expected.map((v: number) => 3 * v)); assertEquals([...tree.nlrValues()], [-30, 27, 300, 30, -3, 3, 0, -27, -300]); assertEquals([...tree.lvlValues()], [-30, 27, -300, 300, -3, 30, 3, -27, 0]);});
Deno.test("BinarySearchTree.from() handles default ascend comparator", () => { const values: number[] = [-10, 9, -1, 100, 9, 1, 0, 9, -100, 10, -9]; const expected: number[] = [-100, -10, -9, -1, 0, 1, 9, 10, 100]; const originalTree: BinarySearchTree<number> = new BinarySearchTree(); for (const value of values) originalTree.insert(value); let tree: BinarySearchTree<number> = BinarySearchTree.from(originalTree); assertEquals([...originalTree], expected); assertEquals([...tree], expected); assertEquals([...tree.nlrValues()], [...originalTree.nlrValues()]); assertEquals([...tree.lvlValues()], [...originalTree.lvlValues()]);
tree = BinarySearchTree.from(originalTree, { compare: descend }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected); assertEquals([...tree.nlrValues()], expected); assertEquals([...tree.lvlValues()], expected);
tree = BinarySearchTree.from(originalTree, { map: (v: number) => 2 * v, }); assertEquals([...originalTree], expected); assertEquals([...tree], expected.map((v: number) => 2 * v));
const math = new MyMath(); tree = BinarySearchTree.from(originalTree, { map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals([...originalTree], expected); assertEquals([...tree], expected.map((v: number) => 3 * v));
tree = BinarySearchTree.from(originalTree, { compare: descend, map: (v: number) => 2 * v, }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected.map((v: number) => 2 * v));
tree = BinarySearchTree.from(originalTree, { compare: descend, map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected.map((v: number) => 3 * v));});
Deno.test("BinarySearchTree.from() handles descend comparator", () => { const values: number[] = [-10, 9, -1, 100, 9, 1, 0, 9, -100, 10, -9]; const expected: number[] = [100, 10, 9, 1, 0, -1, -9, -10, -100]; const originalTree = new BinarySearchTree<number>(descend); for (const value of values) originalTree.insert(value); let tree: BinarySearchTree<number> = BinarySearchTree.from(originalTree); assertEquals([...originalTree], expected); assertEquals([...tree], expected); assertEquals([...tree.nlrValues()], [...originalTree.nlrValues()]); assertEquals([...tree.lvlValues()], [...originalTree.lvlValues()]);
tree = BinarySearchTree.from(originalTree, { compare: ascend }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected); assertEquals([...tree.nlrValues()], expected); assertEquals([...tree.lvlValues()], expected);
tree = BinarySearchTree.from(originalTree, { map: (v: number) => 2 * v, }); assertEquals([...originalTree], expected); assertEquals([...tree], expected.map((v: number) => 2 * v));
const math = new MyMath(); tree = BinarySearchTree.from(originalTree, { map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals([...originalTree], expected); assertEquals([...tree], expected.map((v: number) => 3 * v));
tree = BinarySearchTree.from(originalTree, { compare: ascend, map: (v: number) => 2 * v, }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected.map((v: number) => 2 * v));
tree = BinarySearchTree.from(originalTree, { compare: ascend, map: function (this: MyMath, v: number) { return this.multiply(3, v); }, thisArg: math, }); assertEquals([...originalTree], expected); assertEquals([...tree].reverse(), expected.map((v: number) => 3 * v));});
Deno.test("BinarySearchTree handles README example", () => { const values = [3, 10, 13, 4, 6, 7, 1, 14]; 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); assertEquals(tree.max(), 14); assertEquals(tree.find(42), null); assertEquals(tree.find(7), 7); assertEquals(tree.remove(42), false); assertEquals(tree.remove(7), true); assertEquals([...tree], [1, 3, 4, 6, 10, 13, 14]);
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); assertEquals(invertedTree.max(), 1); assertEquals(invertedTree.find(42), null); assertEquals(invertedTree.find(7), 7); assertEquals(invertedTree.remove(42), false); assertEquals(invertedTree.remove(7), true); assertEquals([...invertedTree], [14, 13, 10, 6, 4, 3, 1]);
const words = new BinarySearchTree<string>((a, b) => ascend(a.length, b.length) || ascend(a, b) ); ["truck", "car", "helicopter", "tank", "train", "suv", "semi", "van"] .forEach((value) => words.insert(value)); assertEquals([...words], [ "car", "suv", "van", "semi", "tank", "train", "truck", "helicopter", ]); assertEquals(words.min(), "car"); assertEquals(words.max(), "helicopter"); assertEquals(words.find("scooter"), null); assertEquals(words.find("tank"), "tank"); assertEquals(words.remove("scooter"), false); assertEquals(words.remove("tank"), true); assertEquals([...words], [ "car", "suv", "van", "semi", "train", "truck", "helicopter", ]);});
Deno.test("BinarySearchTree.max() handles null ", () => { const tree = BinarySearchTree.from([1]); assert(!tree.isEmpty()); tree.clear(); assertEquals(tree.max(), null);});
Deno.test("BinarySearchTree.clear()", () => { const tree = BinarySearchTree.from([1]); tree.clear(); assert(tree.isEmpty());});
Deno.test("BinarySearchTree.rotateNode()", () => { class MyTree<T> extends BinarySearchTree<T> { rotateNode2() { super.rotateNode(this.root!, "right"); } } const tree = new MyTree(); tree.insert(1); assertThrows(() => tree.rotateNode2());});