Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9f8e763

Browse files
committedApr 3, 2018
Add binary search tree.
1 parent 1c911aa commit 9f8e763

File tree

4 files changed

+178
-0
lines changed

4 files changed

+178
-0
lines changed
 

‎src/data-structures/tree/BinaryTreeNode.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,38 @@ export default class BinaryTreeNode {
1818
return this;
1919
}
2020

21+
removeChild(nodeToRemove) {
22+
if (this.left && this.left === nodeToRemove) {
23+
this.left = null;
24+
return true;
25+
}
26+
27+
if (this.right && this.right === nodeToRemove) {
28+
this.right = null;
29+
return true;
30+
}
31+
32+
return false;
33+
}
34+
35+
replaceChild(nodeToReplace, replacementNode) {
36+
if (!nodeToReplace || !replacementNode) {
37+
return false;
38+
}
39+
40+
if (this.left && this.left === nodeToReplace) {
41+
this.left = replacementNode;
42+
return true;
43+
}
44+
45+
if (this.right && this.right === nodeToReplace) {
46+
this.right = replacementNode;
47+
return true;
48+
}
49+
50+
return false;
51+
}
52+
2153
traverseInOrder() {
2254
let traverse = [];
2355

‎src/data-structures/tree/__test__/BinaryTreeNode.test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,53 @@ describe('BinaryTreeNode', () => {
5151

5252
expect(rootNode.toString()).toBe('1,2,3');
5353
});
54+
55+
it('should remove child node', () => {
56+
const leftNode = new BinaryTreeNode(1);
57+
const rightNode = new BinaryTreeNode(3);
58+
const rootNode = new BinaryTreeNode(2);
59+
60+
rootNode
61+
.setLeft(leftNode)
62+
.setRight(rightNode);
63+
64+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 3]);
65+
66+
expect(rootNode.removeChild(rootNode.left)).toBeTruthy();
67+
expect(rootNode.traverseInOrder()).toEqual([2, 3]);
68+
69+
expect(rootNode.removeChild(rootNode.right)).toBeTruthy();
70+
expect(rootNode.traverseInOrder()).toEqual([2]);
71+
72+
expect(rootNode.removeChild(rootNode.right)).toBeFalsy();
73+
expect(rootNode.traverseInOrder()).toEqual([2]);
74+
});
75+
76+
it('should replace child node', () => {
77+
const leftNode = new BinaryTreeNode(1);
78+
const rightNode = new BinaryTreeNode(3);
79+
const rootNode = new BinaryTreeNode(2);
80+
81+
rootNode
82+
.setLeft(leftNode)
83+
.setRight(rightNode);
84+
85+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 3]);
86+
87+
const replacementNode = new BinaryTreeNode(5);
88+
rightNode.setRight(replacementNode);
89+
90+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 3, 5]);
91+
92+
expect(rootNode.replaceChild(rootNode.right, rootNode.right.right)).toBeTruthy();
93+
expect(rootNode.right.value).toBe(5);
94+
expect(rootNode.right.right).toBeNull();
95+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);
96+
97+
expect(rootNode.replaceChild(rootNode.right, rootNode.right.right)).toBeFalsy();
98+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);
99+
100+
expect(rootNode.replaceChild(rootNode.right, replacementNode)).toBeTruthy();
101+
expect(rootNode.traverseInOrder()).toEqual([1, 2, 5]);
102+
});
54103
});

‎src/data-structures/tree/binary-search-tree/BinarySearchTree.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,34 @@ export default class BinarySearchTree {
2020
throw new Error('Item not found in the tree');
2121
}
2222

23+
const { parent } = nodeToRemove;
24+
2325
if (!nodeToRemove.left && !nodeToRemove.right) {
2426
// Node is a leaf and thus has no children.
2527
// Just remove the pointer to this node from the parent node.
28+
parent.removeChild(nodeToRemove);
2629
} else if (nodeToRemove.left && nodeToRemove.right) {
2730
// Node has two children.
2831
// Find the next biggest value (minimum value in the right branch)
2932
// and replace current value node with that next biggest value.
33+
const nextBiggerNode = nodeToRemove.right.findMin();
34+
if (nextBiggerNode !== nodeToRemove.right) {
35+
this.remove(nextBiggerNode.value);
36+
nodeToRemove.value = nextBiggerNode.value;
37+
} else {
38+
// In case if next right value is the next bigger one and it doesn't have left child
39+
// then just replace node that is going to be deleted with the right node.
40+
nodeToRemove.value = nodeToRemove.right.value;
41+
nodeToRemove.right = nodeToRemove.right.right;
42+
}
3043
} else {
3144
// Node has only one child.
3245
// Make this child to be a direct child of current node's parent.
46+
if (nodeToRemove.left) {
47+
parent.replaceChild(nodeToRemove, nodeToRemove.left);
48+
} else {
49+
parent.replaceChild(nodeToRemove, nodeToRemove.right);
50+
}
3351
}
3452
}
3553

‎src/data-structures/tree/binary-search-tree/__test__/BinarySearchTree.test.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,83 @@ describe('BinarySearchTree', () => {
3131
expect(bst.contains(20)).toBeTruthy();
3232
expect(bst.contains(40)).toBeFalsy();
3333
});
34+
35+
it('should remove leaf nodes', () => {
36+
const bst = new BinarySearchTree();
37+
38+
bst.insert(10);
39+
bst.insert(20);
40+
bst.insert(5);
41+
42+
expect(bst.toString()).toBe('5,10,20');
43+
44+
bst.remove(5);
45+
expect(bst.toString()).toBe('10,20');
46+
bst.remove(20);
47+
expect(bst.toString()).toBe('10');
48+
});
49+
50+
it('should remove nodes with one child', () => {
51+
const bst = new BinarySearchTree();
52+
53+
bst.insert(10);
54+
bst.insert(20);
55+
bst.insert(5);
56+
bst.insert(30);
57+
58+
expect(bst.toString()).toBe('5,10,20,30');
59+
60+
bst.remove(20);
61+
expect(bst.toString()).toBe('5,10,30');
62+
63+
bst.insert(1);
64+
expect(bst.toString()).toBe('1,5,10,30');
65+
66+
bst.remove(5);
67+
expect(bst.toString()).toBe('1,10,30');
68+
});
69+
70+
it('should remove nodes with two children', () => {
71+
const bst = new BinarySearchTree();
72+
73+
bst.insert(10);
74+
bst.insert(20);
75+
bst.insert(5);
76+
bst.insert(30);
77+
bst.insert(15);
78+
bst.insert(25);
79+
80+
expect(bst.toString()).toBe('5,10,15,20,25,30');
81+
expect(bst.root.find(20).left.value).toBe(15);
82+
expect(bst.root.find(20).right.value).toBe(30);
83+
84+
bst.remove(20);
85+
expect(bst.toString()).toBe('5,10,15,25,30');
86+
87+
bst.remove(15);
88+
expect(bst.toString()).toBe('5,10,25,30');
89+
90+
bst.remove(10);
91+
expect(bst.toString()).toBe('5,25,30');
92+
expect(bst.root.value).toBe(25);
93+
94+
bst.remove(25);
95+
expect(bst.toString()).toBe('5,30');
96+
97+
bst.remove(5);
98+
expect(bst.toString()).toBe('30');
99+
});
100+
101+
it('should throw error when trying to remove not existing node', () => {
102+
const bst = new BinarySearchTree();
103+
104+
bst.insert(10);
105+
bst.insert(20);
106+
107+
function removeNotExistingElementFromTree() {
108+
bst.remove(30);
109+
}
110+
111+
expect(removeNotExistingElementFromTree).toThrow();
112+
});
34113
});

0 commit comments

Comments
 (0)
Please sign in to comment.