Skip to content

Commit e18ebb4

Browse files
committedNov 25, 2017
chapter 09: [Trees]
1 parent b6dfa0f commit e18ebb4

File tree

12 files changed

+866
-0
lines changed

12 files changed

+866
-0
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Work in Progress.
1818
* 06: [Sets](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter06)
1919
* 07: [Dictionaries and Hashes](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter07)
2020
* 08: [Recursion](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter08)
21+
* 09: [Trees](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter09)
2122

2223
### Third Edition Updates
2324

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

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { Compare, defaultCompare } from '../util';
2+
import BinarySearchTree from './binary-search-tree';
3+
import { Node } from './models/node';
4+
5+
const BalanceFactor = {
6+
UNBALANCED_RIGHT: 1,
7+
SLIGHTLY_UNBALANCED_RIGHT: 2,
8+
BALANCED: 3,
9+
SLIGHTLY_UNBALANCED_LEFT: 4,
10+
UNBALANCED_LEFT: 5
11+
};
12+
13+
export default class AVLTree extends BinarySearchTree {
14+
constructor(compareFn = defaultCompare) {
15+
super(compareFn);
16+
this.compareFn = compareFn;
17+
this.root = null;
18+
}
19+
getNodeHeight(node) {
20+
if (node == null) {
21+
return -1;
22+
}
23+
return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1;
24+
}
25+
/**
26+
* Left left case: rotate right
27+
*
28+
* b a
29+
* / \ / \
30+
* a e -> rotationLL(b) -> c b
31+
* / \ / \
32+
* c d d e
33+
*
34+
* @param node Node<T>
35+
*/
36+
rotationLL(node) {
37+
const tmp = node.left;
38+
node.left = tmp.right;
39+
tmp.right = node;
40+
return tmp;
41+
}
42+
/**
43+
* Right right case: rotate left
44+
*
45+
* a b
46+
* / \ / \
47+
* c b -> rotationRR(a) -> a e
48+
* / \ / \
49+
* d e c d
50+
*
51+
* @param node Node<T>
52+
*/
53+
rotationRR(node) {
54+
const tmp = node.right;
55+
node.right = tmp.left;
56+
tmp.left = node;
57+
return tmp;
58+
}
59+
/**
60+
* Left right case: rotate left then right
61+
* @param node Node<T>
62+
*/
63+
rotationLR(node) {
64+
node.left = this.rotationRR(node.left);
65+
return this.rotationLL(node);
66+
}
67+
/**
68+
* Right left case: rotate right then left
69+
* @param node Node<T>
70+
*/
71+
rotationRL(node) {
72+
node.right = this.rotationLL(node.right);
73+
return this.rotationRR(node);
74+
}
75+
getBalanceFactor(node) {
76+
const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right);
77+
switch (heightDifference) {
78+
case -2:
79+
return BalanceFactor.UNBALANCED_RIGHT;
80+
case -1:
81+
return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT;
82+
case 1:
83+
return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT;
84+
case 2:
85+
return BalanceFactor.UNBALANCED_LEFT;
86+
default:
87+
return BalanceFactor.BALANCED;
88+
}
89+
}
90+
insert(key) {
91+
this.root = this.insertNode(this.root, key);
92+
}
93+
insertNode(node, key) {
94+
if (node == null) {
95+
return new Node(key);
96+
} else if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
97+
node.left = this.insertNode(node.left, key);
98+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
99+
node.right = this.insertNode(node.right, key);
100+
} else {
101+
return node; // duplicated key
102+
}
103+
// verify if tree is balanced
104+
const balanceFactor = this.getBalanceFactor(node);
105+
if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {
106+
if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) {
107+
// Left left case
108+
node = this.rotationLL(node);
109+
} else {
110+
// Left right case
111+
return this.rotationLR(node);
112+
}
113+
}
114+
if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {
115+
if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) {
116+
// Right right case
117+
node = this.rotationRR(node);
118+
} else {
119+
// Right left case
120+
return this.rotationRL(node);
121+
}
122+
}
123+
return node;
124+
}
125+
removeNode(node, key) {
126+
node = super.removeNode(node, key); // {1}
127+
if (node == null) {
128+
return node;
129+
}
130+
// verify if tree is balanced
131+
const balanceFactor = this.getBalanceFactor(node);
132+
if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {
133+
// Left left case
134+
if (
135+
this.getBalanceFactor(node.left) === BalanceFactor.BALANCED ||
136+
this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT
137+
) {
138+
return this.rotationLL(node);
139+
}
140+
// Left right case
141+
if (this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {
142+
return this.rotationLR(node.left);
143+
}
144+
}
145+
if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {
146+
// Right right case
147+
if (
148+
this.getBalanceFactor(node.right) === BalanceFactor.BALANCED ||
149+
this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT
150+
) {
151+
return this.rotationRR(node);
152+
}
153+
// Right left case
154+
if (this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {
155+
return this.rotationRL(node.right);
156+
}
157+
}
158+
return node;
159+
}
160+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { Compare, defaultCompare } from '../util';
2+
import { Node } from './models/node';
3+
4+
export default class BinarySearchTree {
5+
constructor(compareFn = defaultCompare) {
6+
this.compareFn = compareFn;
7+
this.root = null;
8+
}
9+
insert(key) {
10+
// special case: first key
11+
if (this.root == null) {
12+
this.root = new Node(key);
13+
} else {
14+
this.insertNode(this.root, key);
15+
}
16+
}
17+
insertNode(node, key) {
18+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
19+
if (node.left == null) {
20+
node.left = new Node(key);
21+
} else {
22+
this.insertNode(node.left, key);
23+
}
24+
} else {
25+
if (node.right == null) {
26+
node.right = new Node(key);
27+
} else {
28+
this.insertNode(node.right, key);
29+
}
30+
}
31+
}
32+
getRoot() {
33+
return this.root;
34+
}
35+
search(key) {
36+
return this.searchNode(this.root, key);
37+
}
38+
searchNode(node, key) {
39+
if (node == null) {
40+
return false;
41+
}
42+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
43+
return this.searchNode(node.left, key);
44+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
45+
return this.searchNode(node.right, key);
46+
} else {
47+
return true;
48+
}
49+
}
50+
inOrderTraverse(callback) {
51+
this.inOrderTraverseNode(this.root, callback);
52+
}
53+
inOrderTraverseNode(node, callback) {
54+
if (node != null) {
55+
this.inOrderTraverseNode(node.left, callback);
56+
callback(node.key);
57+
this.inOrderTraverseNode(node.right, callback);
58+
}
59+
}
60+
preOrderTraverse(callback) {
61+
this.preOrderTraverseNode(this.root, callback);
62+
}
63+
preOrderTraverseNode(node, callback) {
64+
if (node != null) {
65+
callback(node.key);
66+
this.preOrderTraverseNode(node.left, callback);
67+
this.preOrderTraverseNode(node.right, callback);
68+
}
69+
}
70+
postOrderTraverse(callback) {
71+
this.postOrderTraverseNode(this.root, callback);
72+
}
73+
postOrderTraverseNode(node, callback) {
74+
if (node != null) {
75+
this.postOrderTraverseNode(node.left, callback);
76+
this.postOrderTraverseNode(node.right, callback);
77+
callback(node.key);
78+
}
79+
}
80+
min() {
81+
return this.minNode(this.root);
82+
}
83+
minNode(node) {
84+
let current = node;
85+
while (current != null && current.left != null) {
86+
current = current.left;
87+
}
88+
return current;
89+
}
90+
max() {
91+
return this.maxNode(this.root);
92+
}
93+
maxNode(node) {
94+
let current = node;
95+
while (current != null && current.right != null) {
96+
current = current.right;
97+
}
98+
return current;
99+
}
100+
remove(key) {
101+
this.root = this.removeNode(this.root, key);
102+
}
103+
removeNode(node, key) {
104+
if (node == null) {
105+
return null;
106+
}
107+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
108+
node.left = this.removeNode(node.left, key);
109+
return node;
110+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
111+
node.right = this.removeNode(node.right, key);
112+
return node;
113+
} else {
114+
// key is equal to node.item
115+
// handle 3 special conditions
116+
// 1 - a leaf node
117+
// 2 - a node with only 1 child
118+
// 3 - a node with 2 children
119+
// case 1
120+
if (node.left == null && node.right == null) {
121+
node = null;
122+
return node;
123+
}
124+
// case 2
125+
if (node.left == null) {
126+
node = node.right;
127+
return node;
128+
} else if (node.right == null) {
129+
node = node.left;
130+
return node;
131+
}
132+
// case 3
133+
const aux = this.minNode(node.right);
134+
node.key = aux.key;
135+
node.right = this.removeNode(node.right, aux.key);
136+
return node;
137+
}
138+
}
139+
}

‎src/js/data-structures/models/node.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export class Node {
2+
constructor(key) {
3+
this.key = key;
4+
this.left = null;
5+
this.right = null;
6+
}
7+
toString() {
8+
return `${this.key}`;
9+
}
10+
}

‎src/ts/data-structures/avl-tree.ts

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
import { Compare, defaultCompare, ICompareFunction } from '../util';
2+
import BinarySearchTree from './binary-search-tree';
3+
import { Node } from './models/node';
4+
5+
enum BalanceFactor {
6+
UNBALANCED_RIGHT = 1,
7+
SLIGHTLY_UNBALANCED_RIGHT = 2,
8+
BALANCED = 3,
9+
SLIGHTLY_UNBALANCED_LEFT = 4,
10+
UNBALANCED_LEFT = 5
11+
}
12+
13+
export default class AVLTree<T> extends BinarySearchTree<T> {
14+
15+
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {
16+
super(compareFn);
17+
}
18+
19+
private getNodeHeight(node: Node<T>): number {
20+
if (node == null) {
21+
return -1;
22+
}
23+
return Math.max(this.getNodeHeight(node.left), this.getNodeHeight(node.right)) + 1;
24+
}
25+
26+
/**
27+
* Left left case: rotate right
28+
*
29+
* b a
30+
* / \ / \
31+
* a e -> rotationLL(b) -> c b
32+
* / \ / \
33+
* c d d e
34+
*
35+
* @param node Node<T>
36+
*/
37+
private rotationLL(node: Node<T>) {
38+
const tmp = node.left;
39+
node.left = tmp.right;
40+
tmp.right = node;
41+
return tmp;
42+
}
43+
44+
/**
45+
* Right right case: rotate left
46+
*
47+
* a b
48+
* / \ / \
49+
* c b -> rotationRR(a) -> a e
50+
* / \ / \
51+
* d e c d
52+
*
53+
* @param node Node<T>
54+
*/
55+
private rotationRR(node: Node<T>) {
56+
const tmp = node.right;
57+
node.right = tmp.left;
58+
tmp.left = node;
59+
return tmp;
60+
}
61+
62+
/**
63+
* Left right case: rotate left then right
64+
* @param node Node<T>
65+
*/
66+
private rotationLR(node: Node<T>) {
67+
node.left = this.rotationRR(node.left);
68+
return this.rotationLL(node);
69+
}
70+
71+
/**
72+
* Right left case: rotate right then left
73+
* @param node Node<T>
74+
*/
75+
private rotationRL(node: Node<T>) {
76+
node.right = this.rotationLL(node.right);
77+
return this.rotationRR(node);
78+
}
79+
80+
private getBalanceFactor(node: Node<T>) {
81+
const heightDifference = this.getNodeHeight(node.left) - this.getNodeHeight(node.right);
82+
switch (heightDifference) {
83+
case -2:
84+
return BalanceFactor.UNBALANCED_RIGHT;
85+
case -1:
86+
return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT;
87+
case 1:
88+
return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT;
89+
case 2:
90+
return BalanceFactor.UNBALANCED_LEFT;
91+
default:
92+
return BalanceFactor.BALANCED;
93+
}
94+
}
95+
96+
insert(key: T) {
97+
this.root = this.insertNode(this.root, key);
98+
}
99+
100+
protected insertNode(node: Node<T>, key: T) {
101+
if (node == null) {
102+
return new Node(key);
103+
} else if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
104+
node.left = this.insertNode(node.left, key);
105+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
106+
node.right = this.insertNode(node.right, key);
107+
} else {
108+
return node; // duplicated key
109+
}
110+
111+
// verify if tree is balanced
112+
const balanceState = this.getBalanceFactor(node);
113+
114+
if (balanceState === BalanceFactor.UNBALANCED_LEFT) {
115+
if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) {
116+
// Left left case
117+
node = this.rotationLL(node);
118+
} else {
119+
// Left right case
120+
return this.rotationLR(node);
121+
}
122+
}
123+
124+
if (balanceState === BalanceFactor.UNBALANCED_RIGHT) {
125+
if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) {
126+
// Right right case
127+
node = this.rotationRR(node);
128+
} else {
129+
// Right left case
130+
return this.rotationRL(node);
131+
}
132+
}
133+
134+
return node;
135+
}
136+
137+
protected removeNode(node: Node<T>, key: T) {
138+
if (node == null) {
139+
return null;
140+
}
141+
142+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
143+
// The key to be deleted is in the left sub-tree
144+
node.left = this.removeNode(node.left, key);
145+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
146+
// The key to be deleted is in the right sub-tree
147+
node.right = this.removeNode(node.right, key);
148+
} else {
149+
// node is the node to be deleted
150+
if (node.left == null && node.right == null) {
151+
node = null;
152+
} else if (node.left == null && node.right != null) {
153+
node = node.right;
154+
} else if (node.left != null && node.right == null) {
155+
node = node.left;
156+
} else {
157+
// node has 2 children, get the in-order successor
158+
const inOrderSuccessor = this.minNode(node.right);
159+
node.key = inOrderSuccessor.key;
160+
node.right = this.removeNode(node.right, inOrderSuccessor.key);
161+
}
162+
}
163+
164+
if (node == null) {
165+
return node;
166+
}
167+
168+
// verify if tree is balanced
169+
const balanceState = this.getBalanceFactor(node);
170+
171+
if (balanceState === BalanceFactor.UNBALANCED_LEFT) {
172+
// Left left case
173+
if (
174+
this.getBalanceFactor(node.left) === BalanceFactor.BALANCED ||
175+
this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT
176+
) {
177+
return this.rotationLL(node);
178+
}
179+
// Left right case
180+
if (this.getBalanceFactor(node.left) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT) {
181+
return this.rotationLR(node.left);
182+
}
183+
}
184+
185+
if (balanceState === BalanceFactor.UNBALANCED_RIGHT) {
186+
// Right right case
187+
if (
188+
this.getBalanceFactor(node.right) === BalanceFactor.BALANCED ||
189+
this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT
190+
) {
191+
return this.rotationRR(node);
192+
}
193+
// Right left case
194+
if (this.getBalanceFactor(node.right) === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT) {
195+
return this.rotationRL(node.right);
196+
}
197+
}
198+
199+
return node;
200+
}
201+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { Compare, defaultCompare, ICompareFunction } from '../util';
2+
import { Node } from './models/node';
3+
4+
export default class BinarySearchTree<T> {
5+
protected root: Node<T>;
6+
7+
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {}
8+
9+
insert(key: T) {
10+
// special case: first key
11+
if (this.root == null) {
12+
this.root = new Node(key);
13+
} else {
14+
this.insertNode(this.root, key);
15+
}
16+
}
17+
18+
protected insertNode(node: Node<T>, key: T) {
19+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
20+
if (node.left == null) {
21+
node.left = new Node(key);
22+
} else {
23+
this.insertNode(node.left, key);
24+
}
25+
} else {
26+
if (node.right == null) {
27+
node.right = new Node(key);
28+
} else {
29+
this.insertNode(node.right, key);
30+
}
31+
}
32+
}
33+
34+
getRoot() {
35+
return this.root;
36+
}
37+
38+
search(key: T) {
39+
return this.searchNode(this.root, key);
40+
}
41+
42+
private searchNode(node: Node<T>, key: T): boolean {
43+
if (node == null) {
44+
return false;
45+
}
46+
47+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
48+
return this.searchNode(node.left, key);
49+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
50+
return this.searchNode(node.right, key);
51+
} else {
52+
// key is equal to node.item
53+
return true;
54+
}
55+
}
56+
57+
inOrderTraverse(callback: Function) {
58+
this.inOrderTraverseNode(this.root, callback);
59+
}
60+
61+
private inOrderTraverseNode(node: Node<T>, callback: Function) {
62+
if (node != null) {
63+
this.inOrderTraverseNode(node.left, callback);
64+
callback(node.key);
65+
this.inOrderTraverseNode(node.right, callback);
66+
}
67+
}
68+
69+
preOrderTraverse(callback: Function) {
70+
this.preOrderTraverseNode(this.root, callback);
71+
}
72+
73+
private preOrderTraverseNode(node: Node<T>, callback: Function) {
74+
if (node != null) {
75+
callback(node.key);
76+
this.preOrderTraverseNode(node.left, callback);
77+
this.preOrderTraverseNode(node.right, callback);
78+
}
79+
}
80+
81+
postOrderTraverse(callback: Function) {
82+
this.postOrderTraverseNode(this.root, callback);
83+
}
84+
85+
private postOrderTraverseNode(node: Node<T>, callback: Function) {
86+
if (node != null) {
87+
this.postOrderTraverseNode(node.left, callback);
88+
this.postOrderTraverseNode(node.right, callback);
89+
callback(node.key);
90+
}
91+
}
92+
93+
min() {
94+
return this.minNode(this.root);
95+
}
96+
97+
protected minNode(node: Node<T>) {
98+
let current = node;
99+
while (current != null && current.left != null) {
100+
current = current.left;
101+
}
102+
return current;
103+
}
104+
105+
max() {
106+
return this.maxNode(this.root);
107+
}
108+
109+
protected maxNode(node: Node<T>) {
110+
let current = node;
111+
while (current != null && current.right != null) {
112+
current = current.right;
113+
}
114+
return current;
115+
}
116+
117+
remove(key: T) {
118+
this.root = this.removeNode(this.root, key);
119+
}
120+
121+
protected removeNode(node: Node<T>, key: T) {
122+
if (node == null) {
123+
return null;
124+
}
125+
126+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
127+
node.left = this.removeNode(node.left, key);
128+
return node;
129+
} else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
130+
node.right = this.removeNode(node.right, key);
131+
return node;
132+
} else {
133+
// key is equal to node.item
134+
135+
// handle 3 special conditions
136+
// 1 - a leaf node
137+
// 2 - a node with only 1 child
138+
// 3 - a node with 2 children
139+
140+
// case 1
141+
if (node.left == null && node.right == null) {
142+
node = null;
143+
return node;
144+
}
145+
146+
// case 2
147+
if (node.left == null) {
148+
node = node.right;
149+
return node;
150+
} else if (node.right == null) {
151+
node = node.left;
152+
return node;
153+
}
154+
155+
// case 3
156+
const aux = this.minNode(node.right);
157+
node.key = aux.key;
158+
node.right = this.removeNode(node.right, aux.key);
159+
return node;
160+
}
161+
}
162+
}

‎src/ts/data-structures/models/node.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export class Node<K> {
2+
left: Node<K>;
3+
right: Node<K>;
4+
5+
constructor(public key: K) {}
6+
7+
toString() {
8+
return `${this.key}`;
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export enum Colors {
2+
RED = 0,
3+
BLACK = 1
4+
}
5+
6+
export class RedBlackNode<K> {
7+
left: RedBlackNode<K>;
8+
right: RedBlackNode<K>;
9+
color: Colors;
10+
11+
constructor(public key: K) {}
12+
13+
isRed() {
14+
return this.color === Colors.RED;
15+
}
16+
17+
flipColor() {
18+
if (this.color === Colors.RED) {
19+
this.color = Colors.BLACK;
20+
} else {
21+
this.color = Colors.RED;
22+
}
23+
}
24+
25+
toString() {
26+
return `${this.key}`;
27+
}
28+
}
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { Compare, defaultCompare, ICompareFunction } from '../util';
2+
import BinarySearchTree from './binary-search-tree';
3+
import { Node } from './models/node';
4+
5+
export default class RedBlackTree<T> extends BinarySearchTree<T> {
6+
7+
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {
8+
super(compareFn);
9+
}
10+
}

‎src/ts/index.ts

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export { fibonacci as fibonacci} from './others/fibonacci';
2020
export { fibonacciIterative as fibonacciIterative} from './others/fibonacci';
2121
export { fibonacciMemoization as fibonacciMemoization} from './others/fibonacci';
2222

23+
// chapter 08
24+
export { default as BinarySearchTree } from './data-structures/binary-search-tree';
25+
export { default as AVLTree } from './data-structures/avl-tree';
26+
2327

2428
/* import { hotPotato } from './others/hot-potato';
2529
import { palindromeChecker } from './others/palindrome-checker';
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'mocha';
2+
import { expect } from 'chai';
3+
import { AVLTree } from '../../../src/ts/index';
4+
5+
describe('AVLTree', () => {
6+
let tree: AVLTree<number>;
7+
8+
beforeEach(() => {
9+
tree = new AVLTree<number>();
10+
});
11+
12+
it('starts empty', () => {
13+
expect(tree.getRoot()).to.equal(undefined);
14+
});
15+
16+
it('inserts elements in the AVLTree', () => {
17+
expect(tree.getRoot()).to.equal(undefined);
18+
19+
tree.insert(1);
20+
tree.insert(2);
21+
tree.insert(3);
22+
tree.insert(4);
23+
tree.insert(5);
24+
tree.insert(6);
25+
tree.insert(7);
26+
tree.insert(14);
27+
tree.insert(15);
28+
tree.insert(13);
29+
tree.insert(12);
30+
tree.insert(11);
31+
});
32+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import 'mocha';
2+
import { expect } from 'chai';
3+
import { BinarySearchTree } from '../../../src/ts/index';
4+
5+
describe('BinarySearchTree', () => {
6+
let tree: BinarySearchTree<number>;
7+
8+
beforeEach(() => {
9+
tree = new BinarySearchTree<number>();
10+
});
11+
12+
it('starts empty', () => {
13+
expect(tree.getRoot()).to.equal(undefined);
14+
});
15+
16+
function assertNode(node: any, key: number, left: number, right: number) {
17+
18+
if (key != null) {
19+
expect(node.key).to.equal(key);
20+
} else {
21+
expect(node).to.equal(key);
22+
return;
23+
}
24+
25+
if (left != null) {
26+
expect(node.left.key).to.equal(left);
27+
} else {
28+
expect(node.left).to.equal(left);
29+
}
30+
31+
if (right != null) {
32+
expect(node.right.key).to.equal(right);
33+
} else {
34+
expect(node.right).to.equal(right);
35+
}
36+
}
37+
38+
it('inserts elements in the BST', () => {
39+
expect(tree.getRoot()).to.equal(undefined);
40+
41+
tree.insert(11);
42+
tree.insert(7);
43+
tree.insert(15);
44+
tree.insert(5);
45+
tree.insert(3);
46+
tree.insert(9);
47+
tree.insert(8);
48+
tree.insert(10);
49+
tree.insert(13);
50+
tree.insert(12);
51+
tree.insert(14);
52+
tree.insert(20);
53+
tree.insert(18);
54+
tree.insert(25);
55+
56+
let node = tree.getRoot();
57+
assertNode(node, 11, 7, 15);
58+
59+
node = node.left;
60+
assertNode(node, 7, 5, 9);
61+
62+
node = node.left;
63+
assertNode(node, 5, 3, undefined);
64+
65+
node = node.left;
66+
assertNode(node, 3, undefined, undefined);
67+
68+
node = tree.getRoot().left.left.right;
69+
assertNode(node, undefined, undefined, undefined);
70+
71+
node = tree.getRoot().left.right;
72+
assertNode(node, 9, 8, 10);
73+
74+
node = node.left;
75+
assertNode(node, 8, undefined, undefined);
76+
77+
node = tree.getRoot().left.right.right;
78+
assertNode(node, 10, undefined, undefined);
79+
80+
node = tree.getRoot().right;
81+
assertNode(node, 15, 13, 20);
82+
83+
node = node.left;
84+
assertNode(node, 13, 12, 14);
85+
86+
node = node.left;
87+
assertNode(node, 12, undefined, undefined);
88+
89+
node = tree.getRoot().right.left.right;
90+
assertNode(node, 14, undefined, undefined);
91+
92+
node = tree.getRoot().right.right;
93+
assertNode(node, 20, 18, 25);
94+
95+
node = node.left;
96+
assertNode(node, 18, undefined, undefined);
97+
98+
node = tree.getRoot().right.right.right;
99+
assertNode(node, 25, undefined, undefined);
100+
});
101+
102+
it('verifies if element exists', () => {
103+
expect(tree.getRoot()).to.equal(undefined);
104+
});
105+
106+
it('removes a leaf', () => {
107+
expect(tree.getRoot()).to.equal(undefined);
108+
});
109+
});

0 commit comments

Comments
 (0)
Please sign in to comment.