Skip to content

Commit 336945a

Browse files
authored
Merge pull request #15 from imteekay/tree
Binary Tree & Binary Search Tree
2 parents 61b29b3 + 1416d6a commit 336945a

File tree

5 files changed

+486
-1
lines changed

5 files changed

+486
-1
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import { Queue } from '../../queue/queue';
2+
3+
export class BinarySearchTree {
4+
constructor(value) {
5+
this.value = value;
6+
this.left = null;
7+
this.right = null;
8+
}
9+
10+
insertLeft(value) {
11+
if (this.left) {
12+
const node = new BinarySearchTree(value);
13+
node.left = this.left;
14+
this.left = node;
15+
} else {
16+
this.left = new BinarySearchTree(value);
17+
}
18+
}
19+
20+
insertRight(value) {
21+
if (this.right) {
22+
const node = new BinarySearchTree(value);
23+
node.right = this.right;
24+
this.right = node;
25+
} else {
26+
this.right = new BinarySearchTree(value);
27+
}
28+
}
29+
30+
preOrder() {
31+
console.log(this.value);
32+
if (this.left) this.left.preOrder();
33+
if (this.right) this.right.preOrder();
34+
}
35+
36+
inOrder() {
37+
if (this.left) this.left.inOrder();
38+
console.log(this.value);
39+
if (this.right) this.right.inOrder();
40+
}
41+
42+
postOrder() {
43+
if (this.left) this.left.postOrder();
44+
if (this.right) this.right.postOrder();
45+
console.log(this.value);
46+
}
47+
48+
bfs() {
49+
const queue = new Queue();
50+
queue.enqueue(this);
51+
52+
while (!queue.isEmpty()) {
53+
const node = queue.dequeue();
54+
console.log(node.value);
55+
if (node.left) queue.enqueue(node.left);
56+
if (node.right) queue.enqueue(node.right);
57+
}
58+
}
59+
60+
insertNode(value) {
61+
if (value <= this.value && this.left) {
62+
this.left.insertNode(value);
63+
} else if (value <= this.value) {
64+
this.left = new BinarySearchTree(value);
65+
} else if (value > this.value && this.right) {
66+
this.right.insertNode(value);
67+
} else {
68+
this.right = new BinarySearchTree(value);
69+
}
70+
}
71+
72+
findNode(value) {
73+
if (value < this.value && this.left) {
74+
return this.left.findNode(value);
75+
}
76+
77+
if (value > this.value && this.right) {
78+
return this.right.findNode(value);
79+
}
80+
81+
return this.value === value;
82+
}
83+
84+
removeNode(value, parent) {
85+
if (value < this.value && this.left) {
86+
return this.left.removeNode(value, this);
87+
}
88+
89+
if (value < this.value) {
90+
return false;
91+
}
92+
93+
if (value > this.value && this.right) {
94+
return this.right.removeNode(value, this);
95+
}
96+
97+
if (value > this.value) {
98+
return false;
99+
}
100+
101+
if (this.left === null && this.right === null && this == parent.left) {
102+
parent.left = null;
103+
this.clearNode();
104+
return true;
105+
}
106+
107+
if (this.left === null && this.right === null && this == parent.right) {
108+
parent.right = null;
109+
this.clearNode();
110+
return true;
111+
}
112+
113+
if (this.left && this.right === null && this == parent.left) {
114+
parent.left = this.left;
115+
this.clearNode();
116+
return true;
117+
}
118+
119+
if (this.left && this.right === null && this == parent.right) {
120+
parent.right = this.left;
121+
this.clearNode();
122+
return true;
123+
}
124+
125+
if (this.right && this.left === null && this == parent.left) {
126+
parent.left = this.right;
127+
this.clearNode();
128+
return true;
129+
}
130+
131+
if (this.right && this.left === null && this == parent.right) {
132+
parent.right = this.right;
133+
this.clearNode();
134+
return true;
135+
}
136+
137+
this.value = this.right.findMinimumValue();
138+
this.right.removeNode(this.value, this);
139+
return true;
140+
}
141+
142+
clearNode() {
143+
this.value = null;
144+
this.left = null;
145+
this.right = null;
146+
}
147+
148+
findMinimumValue() {
149+
if (this.left) return this.left.findMinimumValue();
150+
return this.value;
151+
}
152+
}
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import { describe, expect, it } from 'vitest';
2+
import { BinarySearchTree } from '.';
3+
4+
function buildBST() {
5+
const tree = new BinarySearchTree(50);
6+
7+
tree.insertNode(21);
8+
tree.insertNode(4);
9+
tree.insertNode(32);
10+
tree.insertNode(76);
11+
tree.insertNode(64);
12+
tree.insertNode(52);
13+
tree.insertNode(100);
14+
15+
return tree;
16+
}
17+
18+
describe('BinarySearchTree', () => {
19+
it('instantiates a BinarySearchTree', () => {
20+
const tree = new BinarySearchTree('a');
21+
expect(tree.value).toEqual('a');
22+
expect(tree.right).toEqual(null);
23+
expect(tree.left).toEqual(null);
24+
});
25+
26+
describe('inserts a left node', () => {
27+
it('with a left child', () => {
28+
const tree = new BinarySearchTree('a');
29+
tree.left = new BinarySearchTree('b');
30+
tree.insertLeft('c');
31+
expect(tree.left.value).toEqual('c');
32+
expect(tree.left.left.value).toEqual('b');
33+
});
34+
35+
it('without a left child', () => {
36+
const tree = new BinarySearchTree('a');
37+
tree.insertLeft('b');
38+
expect(tree.left.value).toEqual('b');
39+
});
40+
});
41+
42+
describe('inserts a right node', () => {
43+
it('with a right child', () => {
44+
const tree = new BinarySearchTree('a');
45+
tree.right = new BinarySearchTree('b');
46+
tree.insertRight('c');
47+
expect(tree.right.value).toEqual('c');
48+
expect(tree.right.right.value).toEqual('b');
49+
});
50+
51+
it('without a right child', () => {
52+
const tree = new BinarySearchTree('a');
53+
tree.insertRight('b');
54+
expect(tree.right.value).toEqual('b');
55+
});
56+
});
57+
58+
describe('traversal', () => {
59+
const root = new BinarySearchTree(1);
60+
const two = new BinarySearchTree(2);
61+
const three = new BinarySearchTree(3);
62+
const four = new BinarySearchTree(4);
63+
const five = new BinarySearchTree(5);
64+
const six = new BinarySearchTree(6);
65+
const seven = new BinarySearchTree(7);
66+
67+
two.left = three;
68+
two.right = four;
69+
70+
five.left = six;
71+
five.right = seven;
72+
73+
root.left = two;
74+
root.right = five;
75+
76+
it('traverses in pre order', () => {
77+
console.log('====== pre order ======');
78+
root.preOrder();
79+
console.log('====== // ======');
80+
});
81+
82+
it('traverses in order', () => {
83+
console.log('====== in order ======');
84+
root.inOrder();
85+
console.log('====== // ======');
86+
});
87+
88+
it('traverses in post order', () => {
89+
console.log('====== post order ======');
90+
root.postOrder();
91+
console.log('====== // ======');
92+
});
93+
94+
it('traverses via breadth first search', () => {
95+
console.log('====== bfs ======');
96+
root.bfs();
97+
console.log('====== // ======');
98+
});
99+
});
100+
101+
it('inserts nodes to the BST', () => {
102+
const tree = buildBST();
103+
104+
expect(tree.value).toEqual(50);
105+
expect(tree.left.value).toEqual(21);
106+
expect(tree.left.left.value).toEqual(4);
107+
expect(tree.left.right.value).toEqual(32);
108+
expect(tree.right.value).toEqual(76);
109+
expect(tree.right.left.value).toEqual(64);
110+
expect(tree.right.left.left.value).toEqual(52);
111+
expect(tree.right.right.value).toEqual(100);
112+
});
113+
114+
describe('findNode', () => {
115+
it('finds the node in the tree', () => {
116+
const tree = buildBST();
117+
118+
expect(tree.findNode(50)).toEqual(true);
119+
expect(tree.findNode(21)).toEqual(true);
120+
expect(tree.findNode(4)).toEqual(true);
121+
expect(tree.findNode(32)).toEqual(true);
122+
expect(tree.findNode(76)).toEqual(true);
123+
expect(tree.findNode(64)).toEqual(true);
124+
expect(tree.findNode(52)).toEqual(true);
125+
expect(tree.findNode(100)).toEqual(true);
126+
expect(tree.findNode(0)).toEqual(false);
127+
expect(tree.findNode(999)).toEqual(false);
128+
});
129+
});
130+
131+
describe('removeNode', () => {
132+
it('removes a node in the tree', () => {
133+
const tree = buildBST();
134+
135+
expect(tree.findNode(4)).toEqual(true);
136+
expect(tree.removeNode(4)).toEqual(true);
137+
expect(tree.findNode(4)).toEqual(false);
138+
});
139+
140+
it('removes a node in the middle of the left subtree', () => {
141+
const tree = buildBST();
142+
143+
expect(tree.findNode(21)).toEqual(true);
144+
expect(tree.removeNode(21)).toEqual(true);
145+
expect(tree.findNode(21)).toEqual(false);
146+
147+
expect(tree.value).toEqual(50);
148+
expect(tree.left.value).toEqual(32);
149+
expect(tree.left.left.value).toEqual(4);
150+
expect(tree.right.value).toEqual(76);
151+
expect(tree.right.left.value).toEqual(64);
152+
expect(tree.right.left.left.value).toEqual(52);
153+
expect(tree.right.right.value).toEqual(100);
154+
});
155+
156+
it('removes a node in the middle of the right subtree', () => {
157+
const tree = buildBST();
158+
159+
expect(tree.findNode(76)).toEqual(true);
160+
expect(tree.removeNode(76)).toEqual(true);
161+
expect(tree.findNode(76)).toEqual(false);
162+
163+
expect(tree.value).toEqual(50);
164+
expect(tree.left.value).toEqual(21);
165+
expect(tree.left.left.value).toEqual(4);
166+
expect(tree.left.right.value).toEqual(32);
167+
expect(tree.right.value).toEqual(100);
168+
expect(tree.right.left.value).toEqual(64);
169+
expect(tree.right.left.left.value).toEqual(52);
170+
});
171+
172+
it('removes the root node', () => {
173+
const tree = buildBST();
174+
175+
expect(tree.findNode(50)).toEqual(true);
176+
expect(tree.removeNode(50)).toEqual(true);
177+
expect(tree.findNode(50)).toEqual(false);
178+
179+
expect(tree.value).toEqual(52);
180+
expect(tree.left.value).toEqual(21);
181+
expect(tree.left.left.value).toEqual(4);
182+
expect(tree.left.right.value).toEqual(32);
183+
expect(tree.right.value).toEqual(76);
184+
expect(tree.right.right.value).toEqual(100);
185+
expect(tree.right.left.value).toEqual(64);
186+
});
187+
});
188+
});

0 commit comments

Comments
 (0)