min-heap-typed 1.41.1 → 1.41.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-structures/binary-tree/binary-tree.d.ts +9 -9
- package/dist/data-structures/binary-tree/binary-tree.js +2 -5
- package/dist/data-structures/binary-tree/rb-tree.d.ts +17 -2
- package/dist/data-structures/binary-tree/rb-tree.js +87 -20
- package/package.json +2 -2
- package/src/data-structures/binary-tree/binary-tree.ts +13 -13
- package/src/data-structures/binary-tree/rb-tree.ts +94 -20
|
@@ -174,15 +174,15 @@ export declare class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = Binary
|
|
|
174
174
|
getNodes<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, onlyOne?: boolean, beginRoot?: N | null, iterationType?: IterationType): N[];
|
|
175
175
|
getNodes<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, onlyOne?: boolean, beginRoot?: N | null, iterationType?: IterationType): N[];
|
|
176
176
|
getNodes<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C, onlyOne?: boolean, beginRoot?: N | null, iterationType?: IterationType): N[];
|
|
177
|
-
has<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N, iterationType?: IterationType): boolean;
|
|
178
|
-
has<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N, iterationType?: IterationType): boolean;
|
|
179
|
-
has<C extends BTNCallback<N>>(identifier: ReturnType<C> | null, callback: C, beginRoot?: N, iterationType?: IterationType): boolean;
|
|
180
|
-
getNode<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N, iterationType?: IterationType): N | null;
|
|
181
|
-
getNode<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N, iterationType?: IterationType): N | null;
|
|
182
|
-
getNode<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C, beginRoot?: N, iterationType?: IterationType): N | null;
|
|
183
|
-
get<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N, iterationType?: IterationType): V | undefined;
|
|
184
|
-
get<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N, iterationType?: IterationType): V | undefined;
|
|
185
|
-
get<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C, beginRoot?: N, iterationType?: IterationType): V | undefined;
|
|
177
|
+
has<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N | null, iterationType?: IterationType): boolean;
|
|
178
|
+
has<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N | null, iterationType?: IterationType): boolean;
|
|
179
|
+
has<C extends BTNCallback<N>>(identifier: ReturnType<C> | null, callback: C, beginRoot?: N | null, iterationType?: IterationType): boolean;
|
|
180
|
+
getNode<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N | null, iterationType?: IterationType): N | null;
|
|
181
|
+
getNode<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N | null, iterationType?: IterationType): N | null;
|
|
182
|
+
getNode<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C, beginRoot?: N | null, iterationType?: IterationType): N | null;
|
|
183
|
+
get<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C, beginRoot?: N | null, iterationType?: IterationType): V | undefined;
|
|
184
|
+
get<C extends BTNCallback<N, N>>(identifier: N | null, callback?: C, beginRoot?: N | null, iterationType?: IterationType): V | undefined;
|
|
185
|
+
get<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C, beginRoot?: N | null, iterationType?: IterationType): V | undefined;
|
|
186
186
|
/**
|
|
187
187
|
* The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
|
|
188
188
|
* up to the root node, with the option to reverse the order of the nodes.
|
|
@@ -503,7 +503,6 @@ class BinaryTree {
|
|
|
503
503
|
has(identifier, callback = ((node) => node.key), beginRoot = this.root, iterationType = this.iterationType) {
|
|
504
504
|
if (identifier instanceof BinaryTreeNode)
|
|
505
505
|
callback = (node => node);
|
|
506
|
-
// TODO may support finding node by value equal
|
|
507
506
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
|
|
508
507
|
}
|
|
509
508
|
/**
|
|
@@ -525,7 +524,6 @@ class BinaryTree {
|
|
|
525
524
|
var _a;
|
|
526
525
|
if (identifier instanceof BinaryTreeNode)
|
|
527
526
|
callback = (node => node);
|
|
528
|
-
// TODO may support finding node by value equal
|
|
529
527
|
return (_a = this.getNodes(identifier, callback, true, beginRoot, iterationType)[0]) !== null && _a !== void 0 ? _a : null;
|
|
530
528
|
}
|
|
531
529
|
/**
|
|
@@ -544,11 +542,10 @@ class BinaryTree {
|
|
|
544
542
|
* @returns either the found value (of type V) or undefined if no node value is found.
|
|
545
543
|
*/
|
|
546
544
|
get(identifier, callback = ((node) => node.key), beginRoot = this.root, iterationType = this.iterationType) {
|
|
547
|
-
var _a;
|
|
545
|
+
var _a, _b;
|
|
548
546
|
if (identifier instanceof BinaryTreeNode)
|
|
549
547
|
callback = (node => node);
|
|
550
|
-
|
|
551
|
-
return (_a = this.getNodes(identifier, callback, true, beginRoot, iterationType)[0].value) !== null && _a !== void 0 ? _a : undefined;
|
|
548
|
+
return (_b = (_a = this.getNode(identifier, callback, beginRoot, iterationType)) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : undefined;
|
|
552
549
|
}
|
|
553
550
|
/**
|
|
554
551
|
* The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* data-structure-typed
|
|
3
|
+
*
|
|
4
|
+
* @author Tyler Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
|
+
* @license MIT License
|
|
7
|
+
*/
|
|
1
8
|
import { RBTNColor } from '../../types';
|
|
2
9
|
export declare class RBTreeNode {
|
|
3
10
|
key: number;
|
|
@@ -7,7 +14,14 @@ export declare class RBTreeNode {
|
|
|
7
14
|
color: number;
|
|
8
15
|
constructor(key: number, color?: RBTNColor);
|
|
9
16
|
}
|
|
10
|
-
export declare const
|
|
17
|
+
export declare const NIL: RBTreeNode;
|
|
18
|
+
/**
|
|
19
|
+
* 1. Each node is either red or black.
|
|
20
|
+
* 2. The root node is always black.
|
|
21
|
+
* 3. Leaf nodes are typically NIL nodes and are considered black.
|
|
22
|
+
* 4. Red nodes must have black children.
|
|
23
|
+
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
|
|
24
|
+
*/
|
|
11
25
|
export declare class RedBlackTree {
|
|
12
26
|
constructor();
|
|
13
27
|
protected _root: RBTreeNode;
|
|
@@ -28,7 +42,7 @@ export declare class RedBlackTree {
|
|
|
28
42
|
* @returns The `delete` function does not return anything. It has a return type of `void`.
|
|
29
43
|
*/
|
|
30
44
|
delete(key: number): void;
|
|
31
|
-
isRealNode(node: RBTreeNode): node is RBTreeNode;
|
|
45
|
+
isRealNode(node: RBTreeNode | null | undefined): node is RBTreeNode;
|
|
32
46
|
/**
|
|
33
47
|
* The function `getNode` is a recursive depth-first search algorithm that searches for a node with a
|
|
34
48
|
* given key in a red-black tree.
|
|
@@ -66,6 +80,7 @@ export declare class RedBlackTree {
|
|
|
66
80
|
* @returns the predecessor of the given RBTreeNode 'x'.
|
|
67
81
|
*/
|
|
68
82
|
getPredecessor(x: RBTreeNode): RBTreeNode;
|
|
83
|
+
print(beginRoot?: RBTreeNode): void;
|
|
69
84
|
/**
|
|
70
85
|
* The function performs a left rotation on a red-black tree node.
|
|
71
86
|
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* data-structure-typed
|
|
4
|
+
*
|
|
5
|
+
* @author Tyler Zeng
|
|
6
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
7
|
+
* @license MIT License
|
|
8
|
+
*/
|
|
2
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RedBlackTree = exports.
|
|
10
|
+
exports.RedBlackTree = exports.NIL = exports.RBTreeNode = void 0;
|
|
4
11
|
const types_1 = require("../../types");
|
|
5
12
|
class RBTreeNode {
|
|
6
13
|
constructor(key, color = types_1.RBTNColor.BLACK) {
|
|
@@ -13,10 +20,17 @@ class RBTreeNode {
|
|
|
13
20
|
}
|
|
14
21
|
}
|
|
15
22
|
exports.RBTreeNode = RBTreeNode;
|
|
16
|
-
exports.
|
|
23
|
+
exports.NIL = new RBTreeNode(0);
|
|
24
|
+
/**
|
|
25
|
+
* 1. Each node is either red or black.
|
|
26
|
+
* 2. The root node is always black.
|
|
27
|
+
* 3. Leaf nodes are typically NIL nodes and are considered black.
|
|
28
|
+
* 4. Red nodes must have black children.
|
|
29
|
+
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
|
|
30
|
+
*/
|
|
17
31
|
class RedBlackTree {
|
|
18
32
|
constructor() {
|
|
19
|
-
this._root = exports.
|
|
33
|
+
this._root = exports.NIL;
|
|
20
34
|
}
|
|
21
35
|
get root() {
|
|
22
36
|
return this._root;
|
|
@@ -30,11 +44,11 @@ class RedBlackTree {
|
|
|
30
44
|
*/
|
|
31
45
|
insert(key) {
|
|
32
46
|
const node = new RBTreeNode(key, types_1.RBTNColor.RED);
|
|
33
|
-
node.left = exports.
|
|
34
|
-
node.right = exports.
|
|
47
|
+
node.left = exports.NIL;
|
|
48
|
+
node.right = exports.NIL;
|
|
35
49
|
let y = null;
|
|
36
50
|
let x = this.root;
|
|
37
|
-
while (x !== exports.
|
|
51
|
+
while (x !== exports.NIL) {
|
|
38
52
|
y = x;
|
|
39
53
|
if (node.key < x.key) {
|
|
40
54
|
x = x.left;
|
|
@@ -71,9 +85,9 @@ class RedBlackTree {
|
|
|
71
85
|
*/
|
|
72
86
|
delete(key) {
|
|
73
87
|
const helper = (node) => {
|
|
74
|
-
let z = exports.
|
|
88
|
+
let z = exports.NIL;
|
|
75
89
|
let x, y;
|
|
76
|
-
while (node !== exports.
|
|
90
|
+
while (node !== exports.NIL) {
|
|
77
91
|
if (node.key === key) {
|
|
78
92
|
z = node;
|
|
79
93
|
}
|
|
@@ -84,16 +98,16 @@ class RedBlackTree {
|
|
|
84
98
|
node = node.left;
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
|
-
if (z === exports.
|
|
101
|
+
if (z === exports.NIL) {
|
|
88
102
|
return;
|
|
89
103
|
}
|
|
90
104
|
y = z;
|
|
91
105
|
let yOriginalColor = y.color;
|
|
92
|
-
if (z.left === exports.
|
|
106
|
+
if (z.left === exports.NIL) {
|
|
93
107
|
x = z.right;
|
|
94
108
|
this._rbTransplant(z, z.right);
|
|
95
109
|
}
|
|
96
|
-
else if (z.right === exports.
|
|
110
|
+
else if (z.right === exports.NIL) {
|
|
97
111
|
x = z.left;
|
|
98
112
|
this._rbTransplant(z, z.left);
|
|
99
113
|
}
|
|
@@ -121,7 +135,7 @@ class RedBlackTree {
|
|
|
121
135
|
helper(this.root);
|
|
122
136
|
}
|
|
123
137
|
isRealNode(node) {
|
|
124
|
-
return node !== exports.
|
|
138
|
+
return node !== exports.NIL && node !== null;
|
|
125
139
|
}
|
|
126
140
|
/**
|
|
127
141
|
* The function `getNode` is a recursive depth-first search algorithm that searches for a node with a
|
|
@@ -156,7 +170,7 @@ class RedBlackTree {
|
|
|
156
170
|
* @returns The leftmost node in the given RBTreeNode.
|
|
157
171
|
*/
|
|
158
172
|
getLeftMost(node = this.root) {
|
|
159
|
-
while (node.left !== null && node.left !== exports.
|
|
173
|
+
while (node.left !== null && node.left !== exports.NIL) {
|
|
160
174
|
node = node.left;
|
|
161
175
|
}
|
|
162
176
|
return node;
|
|
@@ -167,7 +181,7 @@ class RedBlackTree {
|
|
|
167
181
|
* @returns the rightmost node in a red-black tree.
|
|
168
182
|
*/
|
|
169
183
|
getRightMost(node) {
|
|
170
|
-
while (node.right !== null && node.right !== exports.
|
|
184
|
+
while (node.right !== null && node.right !== exports.NIL) {
|
|
171
185
|
node = node.right;
|
|
172
186
|
}
|
|
173
187
|
return node;
|
|
@@ -178,11 +192,11 @@ class RedBlackTree {
|
|
|
178
192
|
* @returns the successor of the given RBTreeNode.
|
|
179
193
|
*/
|
|
180
194
|
getSuccessor(x) {
|
|
181
|
-
if (x.right !== exports.
|
|
195
|
+
if (x.right !== exports.NIL) {
|
|
182
196
|
return this.getLeftMost(x.right);
|
|
183
197
|
}
|
|
184
198
|
let y = x.parent;
|
|
185
|
-
while (y !== exports.
|
|
199
|
+
while (y !== exports.NIL && y !== null && x === y.right) {
|
|
186
200
|
x = y;
|
|
187
201
|
y = y.parent;
|
|
188
202
|
}
|
|
@@ -195,16 +209,69 @@ class RedBlackTree {
|
|
|
195
209
|
* @returns the predecessor of the given RBTreeNode 'x'.
|
|
196
210
|
*/
|
|
197
211
|
getPredecessor(x) {
|
|
198
|
-
if (x.left !== exports.
|
|
212
|
+
if (x.left !== exports.NIL) {
|
|
199
213
|
return this.getRightMost(x.left);
|
|
200
214
|
}
|
|
201
215
|
let y = x.parent;
|
|
202
|
-
while (y !== exports.
|
|
216
|
+
while (y !== exports.NIL && x === y.left) {
|
|
203
217
|
x = y;
|
|
204
218
|
y = y.parent;
|
|
205
219
|
}
|
|
206
220
|
return y;
|
|
207
221
|
}
|
|
222
|
+
print(beginRoot = this.root) {
|
|
223
|
+
const display = (root) => {
|
|
224
|
+
const [lines, , ,] = _displayAux(root);
|
|
225
|
+
for (const line of lines) {
|
|
226
|
+
console.log(line);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const _displayAux = (node) => {
|
|
230
|
+
if (node === null) {
|
|
231
|
+
return [[], 0, 0, 0];
|
|
232
|
+
}
|
|
233
|
+
if (node.right === null && node.left === null) {
|
|
234
|
+
const line = `${node.key}`;
|
|
235
|
+
const width = line.length;
|
|
236
|
+
const height = 1;
|
|
237
|
+
const middle = Math.floor(width / 2);
|
|
238
|
+
return [[line], width, height, middle];
|
|
239
|
+
}
|
|
240
|
+
if (node.right === null) {
|
|
241
|
+
const [lines, n, p, x] = _displayAux(node.left);
|
|
242
|
+
const s = `${node.key}`;
|
|
243
|
+
const u = s.length;
|
|
244
|
+
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s;
|
|
245
|
+
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u);
|
|
246
|
+
const shifted_lines = lines.map(line => line + ' '.repeat(u));
|
|
247
|
+
return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)];
|
|
248
|
+
}
|
|
249
|
+
if (node.left === null) {
|
|
250
|
+
const [lines, n, p, u] = _displayAux(node.right);
|
|
251
|
+
const s = `${node.key}`;
|
|
252
|
+
const x = s.length;
|
|
253
|
+
const first_line = s + '_'.repeat(x) + ' '.repeat(n - x);
|
|
254
|
+
const second_line = ' '.repeat(u + x) + '\\' + ' '.repeat(n - x - 1);
|
|
255
|
+
const shifted_lines = lines.map(line => ' '.repeat(u) + line);
|
|
256
|
+
return [[first_line, second_line, ...shifted_lines], n + x, p + 2, Math.floor(u / 2)];
|
|
257
|
+
}
|
|
258
|
+
const [left, n, p, x] = _displayAux(node.left);
|
|
259
|
+
const [right, m, q, y] = _displayAux(node.right);
|
|
260
|
+
const s = `${node.key}`;
|
|
261
|
+
const u = s.length;
|
|
262
|
+
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s + '_'.repeat(y) + ' '.repeat(m - y);
|
|
263
|
+
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u + y) + '\\' + ' '.repeat(m - y - 1);
|
|
264
|
+
if (p < q) {
|
|
265
|
+
left.push(...new Array(q - p).fill(' '.repeat(n)));
|
|
266
|
+
}
|
|
267
|
+
else if (q < p) {
|
|
268
|
+
right.push(...new Array(p - q).fill(' '.repeat(m)));
|
|
269
|
+
}
|
|
270
|
+
const zipped_lines = left.map((a, i) => a + ' '.repeat(u) + right[i]);
|
|
271
|
+
return [[first_line, second_line, ...zipped_lines], n + m + u, Math.max(p, q) + 2, n + Math.floor(u / 2)];
|
|
272
|
+
};
|
|
273
|
+
display(beginRoot);
|
|
274
|
+
}
|
|
208
275
|
/**
|
|
209
276
|
* The function performs a left rotation on a red-black tree node.
|
|
210
277
|
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
|
|
@@ -212,7 +279,7 @@ class RedBlackTree {
|
|
|
212
279
|
_leftRotate(x) {
|
|
213
280
|
const y = x.right;
|
|
214
281
|
x.right = y.left;
|
|
215
|
-
if (y.left !== exports.
|
|
282
|
+
if (y.left !== exports.NIL) {
|
|
216
283
|
y.left.parent = x;
|
|
217
284
|
}
|
|
218
285
|
y.parent = x.parent;
|
|
@@ -236,7 +303,7 @@ class RedBlackTree {
|
|
|
236
303
|
_rightRotate(x) {
|
|
237
304
|
const y = x.left;
|
|
238
305
|
x.left = y.right;
|
|
239
|
-
if (y.right !== exports.
|
|
306
|
+
if (y.right !== exports.NIL) {
|
|
240
307
|
y.right.parent = x;
|
|
241
308
|
}
|
|
242
309
|
y.parent = x.parent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "min-heap-typed",
|
|
3
|
-
"version": "1.41.
|
|
3
|
+
"version": "1.41.3",
|
|
4
4
|
"description": "Min Heap. Javascript & Typescript Data Structure.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -131,6 +131,6 @@
|
|
|
131
131
|
"typescript": "^4.9.5"
|
|
132
132
|
},
|
|
133
133
|
"dependencies": {
|
|
134
|
-
"data-structure-typed": "^1.41.
|
|
134
|
+
"data-structure-typed": "^1.41.3"
|
|
135
135
|
}
|
|
136
136
|
}
|
|
@@ -559,21 +559,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|
|
559
559
|
has<C extends BTNCallback<N, BTNKey>>(
|
|
560
560
|
identifier: BTNKey,
|
|
561
561
|
callback?: C,
|
|
562
|
-
beginRoot?: N,
|
|
562
|
+
beginRoot?: N | null,
|
|
563
563
|
iterationType?: IterationType
|
|
564
564
|
): boolean;
|
|
565
565
|
|
|
566
566
|
has<C extends BTNCallback<N, N>>(
|
|
567
567
|
identifier: N | null,
|
|
568
568
|
callback?: C,
|
|
569
|
-
beginRoot?: N,
|
|
569
|
+
beginRoot?: N | null,
|
|
570
570
|
iterationType?: IterationType
|
|
571
571
|
): boolean;
|
|
572
572
|
|
|
573
573
|
has<C extends BTNCallback<N>>(
|
|
574
574
|
identifier: ReturnType<C> | null,
|
|
575
575
|
callback: C,
|
|
576
|
-
beginRoot?: N,
|
|
576
|
+
beginRoot?: N | null,
|
|
577
577
|
iterationType?: IterationType
|
|
578
578
|
): boolean;
|
|
579
579
|
|
|
@@ -601,28 +601,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|
|
601
601
|
iterationType = this.iterationType
|
|
602
602
|
): boolean {
|
|
603
603
|
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
|
604
|
-
|
|
604
|
+
|
|
605
605
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
getNode<C extends BTNCallback<N, BTNKey>>(
|
|
609
609
|
identifier: BTNKey,
|
|
610
610
|
callback?: C,
|
|
611
|
-
beginRoot?: N,
|
|
611
|
+
beginRoot?: N | null,
|
|
612
612
|
iterationType?: IterationType
|
|
613
613
|
): N | null;
|
|
614
614
|
|
|
615
615
|
getNode<C extends BTNCallback<N, N>>(
|
|
616
616
|
identifier: N | null,
|
|
617
617
|
callback?: C,
|
|
618
|
-
beginRoot?: N,
|
|
618
|
+
beginRoot?: N | null,
|
|
619
619
|
iterationType?: IterationType
|
|
620
620
|
): N | null;
|
|
621
621
|
|
|
622
622
|
getNode<C extends BTNCallback<N>>(
|
|
623
623
|
identifier: ReturnType<C>,
|
|
624
624
|
callback: C,
|
|
625
|
-
beginRoot?: N,
|
|
625
|
+
beginRoot?: N | null,
|
|
626
626
|
iterationType?: IterationType
|
|
627
627
|
): N | null;
|
|
628
628
|
|
|
@@ -648,28 +648,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|
|
648
648
|
iterationType = this.iterationType
|
|
649
649
|
): N | null {
|
|
650
650
|
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
|
651
|
-
|
|
651
|
+
|
|
652
652
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
|
|
653
653
|
}
|
|
654
654
|
|
|
655
655
|
get<C extends BTNCallback<N, BTNKey>>(
|
|
656
656
|
identifier: BTNKey,
|
|
657
657
|
callback?: C,
|
|
658
|
-
beginRoot?: N,
|
|
658
|
+
beginRoot?: N | null,
|
|
659
659
|
iterationType?: IterationType
|
|
660
660
|
): V | undefined;
|
|
661
661
|
|
|
662
662
|
get<C extends BTNCallback<N, N>>(
|
|
663
663
|
identifier: N | null,
|
|
664
664
|
callback?: C,
|
|
665
|
-
beginRoot?: N,
|
|
665
|
+
beginRoot?: N | null,
|
|
666
666
|
iterationType?: IterationType
|
|
667
667
|
): V | undefined;
|
|
668
668
|
|
|
669
669
|
get<C extends BTNCallback<N>>(
|
|
670
670
|
identifier: ReturnType<C>,
|
|
671
671
|
callback: C,
|
|
672
|
-
beginRoot?: N,
|
|
672
|
+
beginRoot?: N | null,
|
|
673
673
|
iterationType?: IterationType
|
|
674
674
|
): V | undefined;
|
|
675
675
|
|
|
@@ -695,8 +695,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
|
|
|
695
695
|
iterationType = this.iterationType
|
|
696
696
|
): V | undefined {
|
|
697
697
|
if ((identifier as any) instanceof BinaryTreeNode) callback = (node => node) as C;
|
|
698
|
-
|
|
699
|
-
return this.
|
|
698
|
+
|
|
699
|
+
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
|
|
700
700
|
}
|
|
701
701
|
|
|
702
702
|
/**
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* data-structure-typed
|
|
3
|
+
*
|
|
4
|
+
* @author Tyler Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
|
+
* @license MIT License
|
|
7
|
+
*/
|
|
8
|
+
|
|
1
9
|
import {RBTNColor} from '../../types';
|
|
2
10
|
|
|
3
11
|
export class RBTreeNode {
|
|
@@ -16,11 +24,18 @@ export class RBTreeNode {
|
|
|
16
24
|
}
|
|
17
25
|
}
|
|
18
26
|
|
|
19
|
-
export const
|
|
27
|
+
export const NIL = new RBTreeNode(0);
|
|
20
28
|
|
|
29
|
+
/**
|
|
30
|
+
* 1. Each node is either red or black.
|
|
31
|
+
* 2. The root node is always black.
|
|
32
|
+
* 3. Leaf nodes are typically NIL nodes and are considered black.
|
|
33
|
+
* 4. Red nodes must have black children.
|
|
34
|
+
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
|
|
35
|
+
*/
|
|
21
36
|
export class RedBlackTree {
|
|
22
37
|
constructor() {
|
|
23
|
-
this._root =
|
|
38
|
+
this._root = NIL;
|
|
24
39
|
}
|
|
25
40
|
|
|
26
41
|
protected _root: RBTreeNode;
|
|
@@ -38,13 +53,13 @@ export class RedBlackTree {
|
|
|
38
53
|
*/
|
|
39
54
|
insert(key: number): void {
|
|
40
55
|
const node: RBTreeNode = new RBTreeNode(key, RBTNColor.RED);
|
|
41
|
-
node.left =
|
|
42
|
-
node.right =
|
|
56
|
+
node.left = NIL;
|
|
57
|
+
node.right = NIL;
|
|
43
58
|
|
|
44
59
|
let y: RBTreeNode = null as unknown as RBTreeNode;
|
|
45
60
|
let x: RBTreeNode = this.root;
|
|
46
61
|
|
|
47
|
-
while (x !==
|
|
62
|
+
while (x !== NIL) {
|
|
48
63
|
y = x;
|
|
49
64
|
if (node.key < x.key) {
|
|
50
65
|
x = x.left;
|
|
@@ -83,9 +98,9 @@ export class RedBlackTree {
|
|
|
83
98
|
*/
|
|
84
99
|
delete(key: number): void {
|
|
85
100
|
const helper = (node: RBTreeNode): void => {
|
|
86
|
-
let z: RBTreeNode =
|
|
101
|
+
let z: RBTreeNode = NIL;
|
|
87
102
|
let x: RBTreeNode, y: RBTreeNode;
|
|
88
|
-
while (node !==
|
|
103
|
+
while (node !== NIL) {
|
|
89
104
|
if (node.key === key) {
|
|
90
105
|
z = node;
|
|
91
106
|
}
|
|
@@ -97,16 +112,16 @@ export class RedBlackTree {
|
|
|
97
112
|
}
|
|
98
113
|
}
|
|
99
114
|
|
|
100
|
-
if (z ===
|
|
115
|
+
if (z === NIL) {
|
|
101
116
|
return;
|
|
102
117
|
}
|
|
103
118
|
|
|
104
119
|
y = z;
|
|
105
120
|
let yOriginalColor: number = y.color;
|
|
106
|
-
if (z.left ===
|
|
121
|
+
if (z.left === NIL) {
|
|
107
122
|
x = z.right;
|
|
108
123
|
this._rbTransplant(z, z.right);
|
|
109
|
-
} else if (z.right ===
|
|
124
|
+
} else if (z.right === NIL) {
|
|
110
125
|
x = z.left;
|
|
111
126
|
this._rbTransplant(z, z.left);
|
|
112
127
|
} else {
|
|
@@ -133,8 +148,8 @@ export class RedBlackTree {
|
|
|
133
148
|
helper(this.root);
|
|
134
149
|
}
|
|
135
150
|
|
|
136
|
-
isRealNode(node: RBTreeNode): node is RBTreeNode {
|
|
137
|
-
return node !==
|
|
151
|
+
isRealNode(node: RBTreeNode | null | undefined): node is RBTreeNode {
|
|
152
|
+
return node !== NIL && node !== null;
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
/**
|
|
@@ -170,7 +185,7 @@ export class RedBlackTree {
|
|
|
170
185
|
* @returns The leftmost node in the given RBTreeNode.
|
|
171
186
|
*/
|
|
172
187
|
getLeftMost(node: RBTreeNode = this.root): RBTreeNode {
|
|
173
|
-
while (node.left !== null && node.left !==
|
|
188
|
+
while (node.left !== null && node.left !== NIL) {
|
|
174
189
|
node = node.left;
|
|
175
190
|
}
|
|
176
191
|
return node;
|
|
@@ -182,7 +197,7 @@ export class RedBlackTree {
|
|
|
182
197
|
* @returns the rightmost node in a red-black tree.
|
|
183
198
|
*/
|
|
184
199
|
getRightMost(node: RBTreeNode): RBTreeNode {
|
|
185
|
-
while (node.right !== null && node.right !==
|
|
200
|
+
while (node.right !== null && node.right !== NIL) {
|
|
186
201
|
node = node.right;
|
|
187
202
|
}
|
|
188
203
|
return node;
|
|
@@ -194,12 +209,12 @@ export class RedBlackTree {
|
|
|
194
209
|
* @returns the successor of the given RBTreeNode.
|
|
195
210
|
*/
|
|
196
211
|
getSuccessor(x: RBTreeNode): RBTreeNode {
|
|
197
|
-
if (x.right !==
|
|
212
|
+
if (x.right !== NIL) {
|
|
198
213
|
return this.getLeftMost(x.right);
|
|
199
214
|
}
|
|
200
215
|
|
|
201
216
|
let y: RBTreeNode = x.parent;
|
|
202
|
-
while (y !==
|
|
217
|
+
while (y !== NIL && y !== null && x === y.right) {
|
|
203
218
|
x = y;
|
|
204
219
|
y = y.parent;
|
|
205
220
|
}
|
|
@@ -213,12 +228,12 @@ export class RedBlackTree {
|
|
|
213
228
|
* @returns the predecessor of the given RBTreeNode 'x'.
|
|
214
229
|
*/
|
|
215
230
|
getPredecessor(x: RBTreeNode): RBTreeNode {
|
|
216
|
-
if (x.left !==
|
|
231
|
+
if (x.left !== NIL) {
|
|
217
232
|
return this.getRightMost(x.left);
|
|
218
233
|
}
|
|
219
234
|
|
|
220
235
|
let y: RBTreeNode = x.parent;
|
|
221
|
-
while (y !==
|
|
236
|
+
while (y !== NIL && x === y.left) {
|
|
222
237
|
x = y;
|
|
223
238
|
y = y.parent;
|
|
224
239
|
}
|
|
@@ -226,6 +241,65 @@ export class RedBlackTree {
|
|
|
226
241
|
return y;
|
|
227
242
|
}
|
|
228
243
|
|
|
244
|
+
print(beginRoot: RBTreeNode = this.root) {
|
|
245
|
+
const display = (root: RBTreeNode | null): void => {
|
|
246
|
+
const [lines, , ,] = _displayAux(root);
|
|
247
|
+
for (const line of lines) {
|
|
248
|
+
console.log(line);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const _displayAux = (node: RBTreeNode | null): [string[], number, number, number] => {
|
|
253
|
+
if (node === null) {
|
|
254
|
+
return [[], 0, 0, 0];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (node.right === null && node.left === null) {
|
|
258
|
+
const line = `${node.key}`;
|
|
259
|
+
const width = line.length;
|
|
260
|
+
const height = 1;
|
|
261
|
+
const middle = Math.floor(width / 2);
|
|
262
|
+
return [[line], width, height, middle];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (node.right === null) {
|
|
266
|
+
const [lines, n, p, x] = _displayAux(node.left);
|
|
267
|
+
const s = `${node.key}`;
|
|
268
|
+
const u = s.length;
|
|
269
|
+
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s;
|
|
270
|
+
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u);
|
|
271
|
+
const shifted_lines = lines.map(line => line + ' '.repeat(u));
|
|
272
|
+
return [[first_line, second_line, ...shifted_lines], n + u, p + 2, n + Math.floor(u / 2)];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (node.left === null) {
|
|
276
|
+
const [lines, n, p, u] = _displayAux(node.right);
|
|
277
|
+
const s = `${node.key}`;
|
|
278
|
+
const x = s.length;
|
|
279
|
+
const first_line = s + '_'.repeat(x) + ' '.repeat(n - x);
|
|
280
|
+
const second_line = ' '.repeat(u + x) + '\\' + ' '.repeat(n - x - 1);
|
|
281
|
+
const shifted_lines = lines.map(line => ' '.repeat(u) + line);
|
|
282
|
+
return [[first_line, second_line, ...shifted_lines], n + x, p + 2, Math.floor(u / 2)];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const [left, n, p, x] = _displayAux(node.left);
|
|
286
|
+
const [right, m, q, y] = _displayAux(node.right);
|
|
287
|
+
const s = `${node.key}`;
|
|
288
|
+
const u = s.length;
|
|
289
|
+
const first_line = ' '.repeat(x + 1) + '_'.repeat(n - x - 1) + s + '_'.repeat(y) + ' '.repeat(m - y);
|
|
290
|
+
const second_line = ' '.repeat(x) + '/' + ' '.repeat(n - x - 1 + u + y) + '\\' + ' '.repeat(m - y - 1);
|
|
291
|
+
if (p < q) {
|
|
292
|
+
left.push(...new Array(q - p).fill(' '.repeat(n)));
|
|
293
|
+
} else if (q < p) {
|
|
294
|
+
right.push(...new Array(p - q).fill(' '.repeat(m)));
|
|
295
|
+
}
|
|
296
|
+
const zipped_lines = left.map((a, i) => a + ' '.repeat(u) + right[i]);
|
|
297
|
+
return [[first_line, second_line, ...zipped_lines], n + m + u, Math.max(p, q) + 2, n + Math.floor(u / 2)];
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
display(beginRoot);
|
|
301
|
+
}
|
|
302
|
+
|
|
229
303
|
/**
|
|
230
304
|
* The function performs a left rotation on a red-black tree node.
|
|
231
305
|
* @param {RBTreeNode} x - The parameter `x` is a RBTreeNode object.
|
|
@@ -233,7 +307,7 @@ export class RedBlackTree {
|
|
|
233
307
|
protected _leftRotate(x: RBTreeNode): void {
|
|
234
308
|
const y: RBTreeNode = x.right;
|
|
235
309
|
x.right = y.left;
|
|
236
|
-
if (y.left !==
|
|
310
|
+
if (y.left !== NIL) {
|
|
237
311
|
y.left.parent = x;
|
|
238
312
|
}
|
|
239
313
|
y.parent = x.parent;
|
|
@@ -256,7 +330,7 @@ export class RedBlackTree {
|
|
|
256
330
|
protected _rightRotate(x: RBTreeNode): void {
|
|
257
331
|
const y: RBTreeNode = x.left;
|
|
258
332
|
x.left = y.right;
|
|
259
|
-
if (y.right !==
|
|
333
|
+
if (y.right !== NIL) {
|
|
260
334
|
y.right.parent = x;
|
|
261
335
|
}
|
|
262
336
|
y.parent = x.parent;
|