Skip to content

Commit b8b7f0f

Browse files
committed
Refactoring BSTs, add BST Sort and tests
1 parent 4241353 commit b8b7f0f

File tree

10 files changed

+390
-43
lines changed

10 files changed

+390
-43
lines changed

src/data-structures/trees/avlTree.ts renamed to src/data-structures/trees/avl.ts

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
import AVLNode from "./avlNode";
1+
import BST from "./bst";
2+
import AVLNode from "./avl_node";
23

4+
import Stack from "../basics/stack";
5+
6+
// TODO: extend vanilla BST to avoid repeated code
37
class AVLTree {
48
root: null | AVLNode;
59
size: number;
@@ -290,7 +294,8 @@ class AVLTree {
290294

291295
// Inserts a node in the right (correct) position and rearrange
292296
// Returns this AVL Tree
293-
// Returns false whether this val is already in this AVL Tree
297+
// Removed: Returns false whether this val is already in this AVL Tree
298+
// Duplicated vals allowed, to change just remove comment returning false
294299
insert = (val: number) => {
295300
let node = new AVLNode(val);
296301
if (this.isEmpty()) {
@@ -301,7 +306,7 @@ class AVLTree {
301306
let current = this.root;
302307
while (current !== null) {
303308
// duplicate val
304-
if (current.val === node.val) return false;
309+
// if (current.val === node.val) return false;
305310
// check left
306311
if (current.val > node.val) {
307312
if (!current.left) {
@@ -378,6 +383,83 @@ class AVLTree {
378383
this.rebalancing(x);
379384
this.size--;
380385
};
386+
387+
// **********************************************************
388+
// TRANSVERSING
389+
// **********************************************************
390+
391+
preOrderTreeWalk = (x: AVLNode | null, arr: number[] = []) => {
392+
if (x) {
393+
arr.push(x.val);
394+
this.preOrderTreeWalk(x.left, arr);
395+
this.preOrderTreeWalk(x.right, arr);
396+
}
397+
// check if all nodes already visited
398+
if (this.size === arr.length) return arr;
399+
};
400+
401+
// to tranverse all BST, in order
402+
// expect x = root in 1st call
403+
inOrderTreeWalk = (
404+
x: AVLNode | null,
405+
arr: number[] = []
406+
): number[] | undefined => {
407+
if (x) {
408+
this.inOrderTreeWalk(x.left, arr);
409+
arr.push(x.val);
410+
this.inOrderTreeWalk(x.right, arr);
411+
}
412+
if (this.size === arr.length) return arr;
413+
};
414+
415+
// to tranverse the BST, only add to arr nodes inside [s,t]
416+
inOrderTreeWalkInterval = (
417+
x: AVLNode | null,
418+
s: number,
419+
t: number,
420+
arr: number[] = []
421+
) => {
422+
if (x) {
423+
this.inOrderTreeWalkInterval(x.left, s, t, arr);
424+
if (x.val >= s && x.val <= t) arr.push(x.val);
425+
this.inOrderTreeWalkInterval(x.right, s, t, arr);
426+
if (x.val === t) return arr;
427+
}
428+
};
429+
430+
inOrderTreeWalkStack = () => {
431+
const stack = new Stack();
432+
const arr: number[] = [];
433+
let current = this.root;
434+
while (stack.size !== 0 || current !== null) {
435+
if (current) {
436+
// stack to remember previous node
437+
stack.push(current);
438+
current = current.left;
439+
} else {
440+
// no left child to add (min available node found)
441+
// come back to previous node
442+
current = stack.pop()!.key;
443+
// To add only insede an interval [s,t]:
444+
// check if s <= current.val <= t
445+
// if we found t we can finish
446+
arr.push(current!.val);
447+
// lets try right child
448+
current = current!.right;
449+
}
450+
}
451+
return arr;
452+
};
453+
454+
posOrderTreeWalk = (x: AVLNode | null, arr: number[] = []) => {
455+
if (x) {
456+
this.preOrderTreeWalk(x.left, arr);
457+
this.preOrderTreeWalk(x.right, arr);
458+
arr.push(x.val);
459+
}
460+
// check if all nodes already visited
461+
if (this.size === arr.length) return arr;
462+
};
381463
}
382464

383-
export = AVLTree;
465+
export default AVLTree;

src/data-structures/trees/avlNode.ts renamed to src/data-structures/trees/avl_node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ class AVLNode {
1111
}
1212
}
1313

14-
export = AVLNode;
14+
export default AVLNode;

src/data-structures/trees/bst.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import binarySearchTree from "./bst";
2+
import BSTNode from "./bst_node";
3+
describe("Test for Binary Search Tree", () => {
4+
// TODO: test basic operations
5+
6+
// TODO: use random arr
7+
test("BST in order between an interval", () => {
8+
const arr = [16, 2, 23, 5, 25, 8, 21, 29, 9, 11, 13, 20, 24];
9+
const nodes: BSTNode[] = [];
10+
const bst = new binarySearchTree();
11+
for (let val of arr) {
12+
const node = bst.insert(val);
13+
if (node) {
14+
nodes.push(node);
15+
}
16+
}
17+
const interval = bst.inOrderTreeWalkInterval(bst.root, arr[3], arr[0]);
18+
expect(interval).toEqual([5, 8, 9, 11, 13, 16]);
19+
});
20+
});

src/data-structures/trees/binarySearchTree.ts renamed to src/data-structures/trees/bst.ts

Lines changed: 90 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import BSTNode from "./bSTNode";
2-
import Queue from "../basics/queue";
1+
import BSTNode from "./bst_node";
32
import Stack from "../basics/stack";
43

4+
// TODO: test
5+
56
class BST {
67
root: null | BSTNode;
78
size: number;
@@ -45,26 +46,26 @@ class BST {
4546
// **********************************************************
4647

4748
// Inserts a node in the right position and rearrange
48-
// Returns this BST
49+
// Returns the inserted node
4950
// Returns false whether this val is already in this BST
5051
insert = (val: number) => {
5152
let node = new BSTNode(val);
5253
if (this.isEmpty()) {
5354
this.size++;
5455
this.root = node;
55-
return this;
56+
return node;
5657
}
5758
let current = this.root;
5859
while (current !== null) {
5960
// duplicate val
60-
if (current.val === node.val) return false;
61+
// if (current.val === node.val) return false;
6162
// check left
6263
if (current.val > node.val) {
6364
if (!current.left) {
6465
node.parent = current;
6566
current.left = node;
6667
this.size++;
67-
return this;
68+
return node;
6869
}
6970
// update current to left
7071
current = current.left;
@@ -74,7 +75,7 @@ class BST {
7475
node.parent = current;
7576
current.right = node;
7677
this.size++;
77-
return this;
78+
return node;
7879
}
7980
// update current
8081
current = current.right;
@@ -86,6 +87,19 @@ class BST {
8687
// SEARCH
8788
// **********************************************************
8889

90+
search = (val: number) => {
91+
if (this.isEmpty()) return false;
92+
let current = this.root;
93+
while (current !== null) {
94+
if (current.val === val) return current;
95+
if (current.val > val) {
96+
current = current.left;
97+
} else {
98+
current = current.right;
99+
}
100+
}
101+
};
102+
89103
// Returns true if this BST contains this val,
90104
// Otherwise returns false
91105
contains = (val: number) => {
@@ -211,7 +225,7 @@ class BST {
211225
// OR the sucessor was prepared in the last if
212226
// Anyway we just transplant and update pointers to left subtree
213227
this.transplant(z, sucessor);
214-
// uodate sucessor left (from null) to left subtree
228+
// update sucessor left (from null) to left subtree
215229
sucessor.left = z.left;
216230
// update left subtree parent (from z) to sucessor
217231
sucessor.left.parent = sucessor;
@@ -223,35 +237,78 @@ class BST {
223237
// TRANSVERSING
224238
// **********************************************************
225239

226-
bfs = () => {
227-
if (!this.root) return undefined;
228-
let q = new Queue();
229-
let visited: Array<number> = [];
230-
let current: BSTNode;
231-
q.enQueue(this.root);
232-
while (q.size !== 0) {
233-
current = q.deQueue()!.key;
234-
visited.push(current.val);
235-
if (current.left) q.enQueue(current.left);
236-
if (current.right) q.enQueue(current.right);
240+
preOrderTreeWalk = (x: BSTNode | null, arr: number[] = []) => {
241+
if (x) {
242+
arr.push(x.val);
243+
this.preOrderTreeWalk(x.left, arr);
244+
this.preOrderTreeWalk(x.right, arr);
245+
}
246+
// check if all nodes already visited
247+
if (this.size === arr.length) return arr;
248+
};
249+
250+
// to tranverse all BST, in order
251+
// expect x = root in 1st call
252+
inOrderTreeWalk = (
253+
x: BSTNode | null,
254+
arr: number[] = []
255+
): number[] | undefined => {
256+
if (x) {
257+
this.inOrderTreeWalk(x.left, arr);
258+
arr.push(x.val);
259+
this.inOrderTreeWalk(x.right, arr);
260+
}
261+
if (this.size === arr.length) return arr;
262+
};
263+
264+
// to tranverse the BST, only add to arr nodes inside [s,t]
265+
inOrderTreeWalkInterval = (
266+
x: BSTNode | null,
267+
s: number,
268+
t: number,
269+
arr: number[] = []
270+
) => {
271+
if (x) {
272+
this.inOrderTreeWalkInterval(x.left, s, t, arr);
273+
if (x.val >= s && x.val <= t) arr.push(x.val);
274+
this.inOrderTreeWalkInterval(x.right, s, t, arr);
275+
if (x.val === t) return arr;
276+
}
277+
};
278+
279+
inOrderTreeWalkStack = () => {
280+
const stack = new Stack();
281+
const arr: number[] = [];
282+
let current = this.root;
283+
while (stack.size !== 0 || current !== null) {
284+
if (current) {
285+
// stack to remember previous node
286+
stack.push(current);
287+
current = current.left;
288+
} else {
289+
// no left child to add (min available node found)
290+
// come back to previous node
291+
current = stack.pop()!.key;
292+
// To add only insede an interval [s,t]:
293+
// check if s <= current.val <= t
294+
// if we found t we can finish
295+
arr.push(current!.val);
296+
// lets try right child
297+
current = current!.right;
298+
}
237299
}
238-
return visited;
300+
return arr;
239301
};
240302

241-
dfsPreOrder = () => {
242-
if (!this.root) return undefined;
243-
let stack = new Stack();
244-
let visited: Array<number> = [];
245-
let current: BSTNode;
246-
stack.push(this.root);
247-
while (stack.size !== 0) {
248-
current = stack.pop()!.key;
249-
visited.push(current.val);
250-
if (current.right) stack.push(current.right);
251-
if (current.left) stack.push(current.left);
303+
posOrderTreeWalk = (x: BSTNode | null, arr: number[] = []) => {
304+
if (x) {
305+
this.preOrderTreeWalk(x.left, arr);
306+
this.preOrderTreeWalk(x.right, arr);
307+
arr.push(x.val);
252308
}
253-
return visited;
309+
// check if all nodes already visited
310+
if (this.size === arr.length) return arr;
254311
};
255312
}
256313

257-
export = BST;
314+
export default BST;

src/data-structures/trees/bSTNode.ts renamed to src/data-structures/trees/bst_node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ class BSTNode {
99
}
1010
}
1111

12-
export = BSTNode;
12+
export default BSTNode;

0 commit comments

Comments
 (0)