Skip to content

Commit 90aaa3c

Browse files
authored
Merge pull request loiane#48 from loiane/third-edition
Third edition
2 parents c3b98b4 + 6be1c4c commit 90aaa3c

File tree

5 files changed

+294
-10
lines changed

5 files changed

+294
-10
lines changed

examples/chapter10/01-UsingMinHeap.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ for (let i = 1; i < 10; i++) {
2222

2323
console.log(heap.getAsArray());
2424

25-
console.log('Extract minimum: ', heap.extract());
25+
console.log('Extract minimum: ', heap.extract()); // 1
2626
console.log(heap.getAsArray()); // [2, 4, 3, 8, 5, 6, 7, 9]
2727

Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
1+
import { Node } from './node';
2+
13
export enum Colors {
24
RED = 0,
35
BLACK = 1
46
}
57

6-
export class RedBlackNode<K> {
8+
export class RedBlackNode<K> extends Node<K> {
79
left: RedBlackNode<K>;
810
right: RedBlackNode<K>;
11+
parent: RedBlackNode<K>;
912
color: Colors;
1013

11-
constructor(public key: K) {}
14+
constructor(public key: K) {
15+
super(key);
16+
this.color = Colors.RED;
17+
}
1218

1319
isRed() {
1420
return this.color === Colors.RED;
@@ -21,8 +27,4 @@ export class RedBlackNode<K> {
2127
this.color = Colors.RED;
2228
}
2329
}
24-
25-
toString() {
26-
return `${this.key}`;
27-
}
2830
}

src/ts/data-structures/red-black-tree.ts

+172-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,180 @@
1-
/*import { Compare, defaultCompare, ICompareFunction } from '../util';
1+
import { defaultCompare, ICompareFunction, Compare } from '../util';
22
import BinarySearchTree from './binary-search-tree';
3-
import { Node } from './models/node';
3+
import { RedBlackNode, Colors } from './models/red-black-node';
44

55
export default class RedBlackTree<T> extends BinarySearchTree<T> {
6+
protected root: RedBlackNode<T>;
67

78
constructor(protected compareFn: ICompareFunction<T> = defaultCompare) {
89
super(compareFn);
910
}
11+
12+
/**
13+
* Left left case: rotate right
14+
*
15+
* b a
16+
* / \ / \
17+
* a e -> rotationLL(b) -> c b
18+
* / \ / \
19+
* c d d e
20+
*
21+
* @param node Node<T>
22+
*/
23+
private rotationLL(node: RedBlackNode<T>) {
24+
const tmp = node.left;
25+
node.left = tmp.right;
26+
if (tmp.right && tmp.right.key) {
27+
tmp.right.parent = node;
28+
}
29+
tmp.parent = node.parent;
30+
if (!node.parent) {
31+
this.root = tmp;
32+
} else {
33+
if (node === node.parent.left) {
34+
node.parent.left = tmp;
35+
} else {
36+
node.parent.right = tmp;
37+
}
38+
}
39+
tmp.right = node;
40+
node.parent = tmp;
41+
}
42+
43+
/**
44+
* Right right case: rotate left
45+
*
46+
* a b
47+
* / \ / \
48+
* c b -> rotationRR(a) -> a e
49+
* / \ / \
50+
* d e c d
51+
*
52+
* @param node Node<T>
53+
*/
54+
private rotationRR(node: RedBlackNode<T>) {
55+
const tmp = node.right;
56+
node.right = tmp.left;
57+
if (tmp.left && tmp.left.key) {
58+
tmp.left.parent = node;
59+
}
60+
tmp.parent = node.parent;
61+
if (!node.parent) {
62+
this.root = tmp;
63+
} else {
64+
if (node === node.parent.left) {
65+
node.parent.left = tmp;
66+
} else {
67+
node.parent.right = tmp;
68+
}
69+
}
70+
tmp.left = node;
71+
node.parent = tmp;
72+
}
73+
74+
insert(key: T) {
75+
// special case: first key
76+
if (this.root == null) {
77+
this.root = new RedBlackNode(key);
78+
this.root.color = Colors.BLACK;
79+
} else {
80+
const newNode = this.insertNode(this.root, key);
81+
this.fixTreeProperties(newNode);
82+
}
83+
}
84+
85+
protected insertNode(node: RedBlackNode<T>, key: T): RedBlackNode<T> {
86+
if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
87+
if (node.left == null) {
88+
node.left = new RedBlackNode(key);
89+
node.left.parent = node;
90+
return node.left;
91+
} else {
92+
return this.insertNode(node.left, key);
93+
}
94+
} else if (node.right == null) {
95+
node.right = new RedBlackNode(key);
96+
node.right.parent = node;
97+
return node.right;
98+
} else {
99+
return this.insertNode(node.right, key);
100+
}
101+
}
102+
103+
private fixTreeProperties(node: RedBlackNode<T>) {
104+
while (node && node.parent && node.parent.color === Colors.RED && node.color !== Colors.BLACK) {
105+
let parent = node.parent;
106+
const grandParent = parent.parent;
107+
108+
// case A
109+
if (grandParent && grandParent.left === parent) {
110+
111+
const uncle = grandParent.right;
112+
113+
// case 1: uncle of node is also red - only recoloring
114+
if (uncle && uncle.color === Colors.RED) {
115+
grandParent.color = Colors.RED;
116+
parent.color = Colors.BLACK;
117+
uncle.color = Colors.BLACK;
118+
node = grandParent;
119+
} else {
120+
// case 2: node is right child - left rotate
121+
if (node === parent.right) {
122+
this.rotationRR(parent);
123+
node = parent;
124+
parent = node.parent;
125+
}
126+
127+
// case 3: node is left child - right rotate
128+
this.rotationLL(grandParent);
129+
// swap color
130+
parent.color = Colors.BLACK;
131+
grandParent.color = Colors.RED;
132+
node = parent;
133+
}
134+
135+
} else { // case B: parent is right child of grand parent
136+
137+
const uncle = grandParent.left;
138+
139+
// case 1: uncle is read - only recoloring
140+
if (uncle && uncle.color === Colors.RED) {
141+
grandParent.color = Colors.RED;
142+
parent.color = Colors.BLACK;
143+
uncle.color = Colors.BLACK;
144+
node = grandParent;
145+
} else {
146+
// case 2: node is left child - left rotate
147+
if (node === parent.left) {
148+
this.rotationLL(parent);
149+
node = parent;
150+
parent = node.parent;
151+
}
152+
153+
// case 3: node is right child - left rotate
154+
this.rotationRR(grandParent);
155+
// swap color
156+
parent.color = Colors.BLACK;
157+
grandParent.color = Colors.RED;
158+
node = parent;
159+
}
160+
}
161+
}
162+
this.root.color = Colors.BLACK;
163+
}
164+
165+
getRoot() {
166+
return this.root;
167+
}
168+
169+
/* private flipColors(node: RedBlackNode<T>) {
170+
node.left.flipColor();
171+
node.right.flipColor();
172+
}
173+
174+
private isRed(node: RedBlackNode<T>) {
175+
if (!node) {
176+
return false;
177+
}
178+
return node.isRed();
179+
}*/
10180
}
11-
*/

src/ts/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export { fibonacciMemoization as fibonacciMemoization} from './others/fibonacci'
2323
// chapter 09
2424
export { default as BinarySearchTree } from './data-structures/binary-search-tree';
2525
export { default as AVLTree } from './data-structures/avl-tree';
26+
export { default as RedBlackTree } from './data-structures/red-black-tree';
2627

2728
// chapter 10
2829
export { MinHeap as MinHeap } from './data-structures/heap';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import { Colors } from './../../../src/ts/data-structures/models/red-black-node';
2+
import 'mocha';
3+
import { expect } from 'chai';
4+
import { RedBlackTree } from '../../../src/ts/index';
5+
6+
describe('RedBlackTree', () => {
7+
let tree: RedBlackTree<number>;
8+
9+
beforeEach(() => {
10+
tree = new RedBlackTree<number>();
11+
});
12+
13+
it('starts empty', () => {
14+
expect(tree.getRoot()).to.equal(undefined);
15+
});
16+
17+
it('inserts elements in the RedBlackTree', () => {
18+
expect(tree.getRoot()).to.equal(undefined);
19+
20+
let node;
21+
22+
tree.insert(1);
23+
assertNode(tree.getRoot(), 1, Colors.BLACK);
24+
25+
tree.insert(2);
26+
assertNode(tree.getRoot(), 1, Colors.BLACK);
27+
assertNode(tree.getRoot().right, 2, Colors.RED);
28+
29+
tree.insert(3);
30+
assertNode(tree.getRoot(), 2, Colors.BLACK);
31+
assertNode(tree.getRoot().right, 3, Colors.RED);
32+
assertNode(tree.getRoot().left, 1, Colors.RED);
33+
34+
tree.insert(4);
35+
assertNode(tree.getRoot(), 2, Colors.BLACK);
36+
assertNode(tree.getRoot().left, 1, Colors.BLACK);
37+
assertNode(tree.getRoot().right, 3, Colors.BLACK);
38+
assertNode(tree.getRoot().right.right, 4, Colors.RED);
39+
40+
tree.insert(5);
41+
assertNode(tree.getRoot(), 2, Colors.BLACK);
42+
assertNode(tree.getRoot().left, 1, Colors.BLACK);
43+
node = tree.getRoot().right;
44+
assertNode(node, 4, Colors.BLACK);
45+
assertNode(node.left, 3, Colors.RED);
46+
assertNode(node.right, 5, Colors.RED);
47+
48+
tree.insert(6);
49+
assertNode(tree.getRoot(), 2, Colors.BLACK);
50+
assertNode(tree.getRoot().left, 1, Colors.BLACK);
51+
node = tree.getRoot().right;
52+
assertNode(node, 4, Colors.RED);
53+
assertNode(node.left, 3, Colors.BLACK);
54+
assertNode(node.right, 5, Colors.BLACK);
55+
assertNode(node.right.right, 6, Colors.RED);
56+
57+
tree.insert(7);
58+
assertNode(tree.getRoot(), 2, Colors.BLACK);
59+
assertNode(tree.getRoot().left, 1, Colors.BLACK);
60+
node = tree.getRoot().right;
61+
assertNode(node, 4, Colors.RED);
62+
assertNode(node.left, 3, Colors.BLACK);
63+
assertNode(node.right, 6, Colors.BLACK);
64+
assertNode(node.right.right, 7, Colors.RED);
65+
assertNode(node.right.left, 5, Colors.RED);
66+
67+
tree.insert(8);
68+
assertNode(tree.getRoot(), 4, Colors.BLACK);
69+
node = tree.getRoot().left;
70+
assertNode(node, 2, Colors.RED);
71+
assertNode(node.left, 1, Colors.BLACK);
72+
assertNode(node.right, 3, Colors.BLACK);
73+
node = tree.getRoot().right;
74+
assertNode(node, 6, Colors.RED);
75+
assertNode(node.left, 5, Colors.BLACK);
76+
assertNode(node.right, 7, Colors.BLACK);
77+
assertNode(node.right.right, 8, Colors.RED);
78+
79+
tree.insert(9);
80+
assertNode(tree.getRoot(), 4, Colors.BLACK);
81+
node = tree.getRoot().left;
82+
assertNode(node, 2, Colors.RED);
83+
assertNode(node.left, 1, Colors.BLACK);
84+
assertNode(node.right, 3, Colors.BLACK);
85+
node = tree.getRoot().right;
86+
assertNode(node, 6, Colors.RED);
87+
assertNode(node.left, 5, Colors.BLACK);
88+
assertNode(node.right, 8, Colors.BLACK);
89+
assertNode(node.right.left, 7, Colors.RED);
90+
assertNode(node.right.right, 9, Colors.RED);
91+
92+
tree.insert(10);
93+
assertNode(tree.getRoot(), 4, Colors.BLACK);
94+
node = tree.getRoot().left;
95+
assertNode(node, 2, Colors.BLACK);
96+
assertNode(node.left, 1, Colors.BLACK);
97+
assertNode(node.right, 3, Colors.BLACK);
98+
node = tree.getRoot().right;
99+
assertNode(node, 6, Colors.BLACK);
100+
assertNode(node.left, 5, Colors.BLACK);
101+
assertNode(node.right, 8, Colors.RED);
102+
assertNode(node.right.left, 7, Colors.BLACK);
103+
assertNode(node.right.right, 9, Colors.BLACK);
104+
assertNode(node.right.right.right, 10, Colors.RED);
105+
106+
});
107+
108+
function assertNode(node, key, color) {
109+
expect(node.color).to.equal(color);
110+
expect(node.key).to.equal(key);
111+
}
112+
});

0 commit comments

Comments
 (0)