Skip to content

Commit

Permalink
Code basic BST. Add some tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
HamsterCoder committed Dec 4, 2023
1 parent f62343f commit 2c885d5
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 1 deletion.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ This repository contains implementations of some data structures and algorithms.

### What do you have?

#### Sorts and shuffles

* Knuth Shuffle - returns a shuffled copy of the array
* Shell Sort - returns a sorted copy of the array
* Quick Sort - returns a sorted copy of the array
* Insertion Sort - returns a sorted copy of the array

#### Data structures
* MaxHeap - allows for `add` and `removeMax` operations (with heapify)
* MinHeap - allows for `add` and `removeMin` operations (with heapify)
* Heap - allows for `add` and `removeRoot` operations (with heapify)
* BinarySearchTree - allows for `set`, `get`, `min`, `max`, iteration (no deletion)

## Development

Expand Down
61 changes: 61 additions & 0 deletions src/BinarySearchTree.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { BinarySearchTree } from "./BinarySearchTree";

describe('BinarySearchTree', () => {
let bst: BinarySearchTree<string, number>;

beforeEach(() => {
bst = new BinarySearchTree((a, b) => a > b ? 1 : (a === b ? 0 : -1));
});

test('Sets and gets one key-value', () => {
bst.set('a', 0);
expect(bst.get('a')).toEqual(0);
expect(bst.root?.count).toEqual(1);
});

test('Sets and gets a pair of key-values', () => {
bst.set('a', 0);
bst.set('b', 1);

for (let node of bst) {
console.log(node?.key, node?.value);
}

expect(bst.get('a')).toEqual(0);
expect(bst.get('b')).toEqual(1);
expect(bst.root?.count).toEqual(2);
});

test('Provides in order iteration', () => {
bst.set('a', 0);
bst.set('b', 1);
bst.set('c', 2);
bst.set('d', 3);
bst.set('e', 4);
bst.set('f', 5);

expect(bst.root?.count).toEqual(6);

let prev;

for (let node of bst) {
if (!prev) {
prev = node;
} else {
expect(bst.compare(node?.key, prev?.key) === 1).toBeTruthy();
}
}
});

test('Returns min and max', () => {
bst.set('a', 0);
bst.set('b', 1);
bst.set('c', 2);
bst.set('d', 3);
bst.set('e', 4);
bst.set('f', 5);

expect(bst.min()?.key).toEqual('a');
expect(bst.max()?.key).toEqual('f');
});
});
122 changes: 122 additions & 0 deletions src/BinarySearchTree.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
export interface TreeNode<K, V> {
key: K;
value: V;
count: number;
left: TreeNode<K, V> | null;
right: TreeNode<K, V> | null;
}

// TODO
// Add this method description to docs
// Rank: how many keys are smaller than k, bigger than k

export class BinarySearchTree<K, V> {
root: TreeNode<K, V> | null = null;
compare: (a: K, b: K) => number;

constructor(compare: (a: K, b: K) => number) {
this.compare = compare;
}

[Symbol.iterator](this: BinarySearchTree<K, V>): Iterator<TreeNode<K, V>> {
const items = this.getSortedNodes(this.root);
let i = 0;
return {
next() {
if (i === items.length) {
return { done: true, value: undefined };
}

return { value: items[i++]};
}
};
}

private getSortedNodes(node: TreeNode<K, V> | null): TreeNode<K, V>[] {
if (node === null) {
return [];
}

return [
...this.getSortedNodes(node.left),
node,
...this.getSortedNodes(node.right)
];
}

get(key: K): V | null {
let root = this.root;

while (root !== null) {
let cmp = this.compare(key, root.key);

if (cmp < 0) {
root = root.left;
} else if (cmp > 0) {
root = root.right;
} else {
return root.value;
}
}

return null;
}

size(node: TreeNode<K, V> | null): number {
if (node === null) {
return 0;
}

return node.count;
}

private _set(node: TreeNode<K, V> | null, key: K, value: V): TreeNode<K, V> {
if (node === null) {
return {
key,
value,
count: 1,
left: null,
right: null,
};
}

let cmp = this.compare(key, node.key);

if (cmp < 0) {
node.left = this._set(node.left, key, value);
} else if (cmp > 0) {
node.right = this._set(node.right, key, value);
} else {
node.value = value;
}

node.count = 1 + this.size(node.left) + this.size(node.right);

return node;
}

set(key: K, value: V): void {
this.root = this._set(this.root, key, value);
}

min(): TreeNode<K, V> | null {
let node = this.root;

while (node?.left) {
node = node.left;
}

return node;
}

max(): TreeNode<K, V> | null {
let node = this.root;

while (node?.right) {
node = node.right;
}

return node;
}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ES5",
"target": "es2015",
"module": "CommonJS",
"rootDir": "src",
"outDir": "dist",
Expand Down

0 comments on commit 2c885d5

Please sign in to comment.