min-heap-typed 1.41.1 → 1.41.2

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.
@@ -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
- // TODO may support finding node by value equal
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 SN: RBTreeNode;
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.SN = exports.RBTreeNode = void 0;
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.SN = new RBTreeNode(0);
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.SN;
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.SN;
34
- node.right = exports.SN;
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.SN) {
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.SN;
88
+ let z = exports.NIL;
75
89
  let x, y;
76
- while (node !== exports.SN) {
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.SN) {
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.SN) {
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.SN) {
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.SN && node !== null;
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.SN) {
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.SN) {
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.SN) {
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.SN && y !== null && x === y.right) {
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.SN) {
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.SN && x === y.left) {
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.SN) {
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.SN) {
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.1",
3
+ "version": "1.41.2",
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.1"
134
+ "data-structure-typed": "^1.41.2"
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
- // TODO may support finding node by value equal
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
- // TODO may support finding node by value equal
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
- // TODO may support finding node by value equal
699
- return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0].value ?? undefined;
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 SN = new RBTreeNode(0);
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 = SN;
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 = SN;
42
- node.right = SN;
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 !== SN) {
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 = SN;
101
+ let z: RBTreeNode = NIL;
87
102
  let x: RBTreeNode, y: RBTreeNode;
88
- while (node !== SN) {
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 === SN) {
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 === SN) {
121
+ if (z.left === NIL) {
107
122
  x = z.right;
108
123
  this._rbTransplant(z, z.right);
109
- } else if (z.right === SN) {
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 !== SN && node !== null;
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 !== SN) {
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 !== SN) {
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 !== SN) {
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 !== SN && y !== null && x === y.right) {
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 !== SN) {
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 !== SN && x === y.left) {
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 !== SN) {
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 !== SN) {
333
+ if (y.right !== NIL) {
260
334
  y.right.parent = x;
261
335
  }
262
336
  y.parent = x.parent;