min-heap-typed 1.50.5 → 1.50.6

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.
@@ -1,21 +1,13 @@
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
-
9
- import {
1
+ import type {
10
2
  BinaryTreeDeleteResult,
11
3
  BSTNKeyOrNode,
12
4
  BTNCallback,
13
5
  KeyOrNodeOrEntry,
14
- RBTNColor,
15
6
  RBTreeOptions,
16
7
  RedBlackTreeNested,
17
8
  RedBlackTreeNodeNested
18
9
  } from '../../types';
10
+ import { RBTNColor } from '../../types';
19
11
  import { BST, BSTNode } from './bst';
20
12
  import { IBinaryTree } from '../../interfaces';
21
13
 
@@ -44,7 +36,7 @@ export class RedBlackTreeNode<
44
36
 
45
37
  /**
46
38
  * The function returns the color value of a variable.
47
- * @returns The color value stored in the protected variable `_color`.
39
+ * @returns The color value stored in the private variable `_color`.
48
40
  */
49
41
  get color(): RBTNColor {
50
42
  return this._color;
@@ -59,13 +51,6 @@ export class RedBlackTreeNode<
59
51
  }
60
52
  }
61
53
 
62
- /**
63
- * 1. Each node is either red or black.
64
- * 2. The root node is always black.
65
- * 3. Leaf nodes are typically Sentinel nodes and are considered black.
66
- * 4. Red nodes must have black children.
67
- * 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
68
- */
69
54
  export class RedBlackTree<
70
55
  K = any,
71
56
  V = any,
@@ -75,40 +60,42 @@ export class RedBlackTree<
75
60
  extends BST<K, V, NODE, TREE>
76
61
  implements IBinaryTree<K, V, NODE, TREE> {
77
62
  /**
78
- * This is the constructor function for a Red-Black Tree data structure in TypeScript, which
79
- * initializes the tree with optional nodes and options.
80
- * @param [keysOrNodesOrEntries] - The `keysOrNodesOrEntries` parameter is an optional iterable of `KeyOrNodeOrEntry<K, V, NODE>`
81
- * objects. It represents the initial nodes that will be added to the RBTree during its
82
- * construction. If this parameter is provided, the `addMany` method is called to add all the
83
- * nodes to the
84
- * @param [options] - The `options` parameter is an optional object that allows you to customize the
85
- * behavior of the RBTree. It is of type `Partial<RBTreeOptions>`, which means that you can provide
86
- * only a subset of the properties defined in the `RBTreeOptions` interface.
63
+ * This is the constructor function for a Red-Black Tree data structure in TypeScript.
64
+ * @param keysOrNodesOrEntries - The `keysOrNodesOrEntries` parameter is an iterable object that can
65
+ * contain keys, nodes, or entries. It is used to initialize the RBTree with the provided keys,
66
+ * nodes, or entries.
67
+ * @param [options] - The `options` parameter is an optional object that can be passed to the
68
+ * constructor. It allows you to customize the behavior of the RBTree. It can include properties such
69
+ * as `compareKeys`, `compareValues`, `allowDuplicates`, etc. These properties define how the RBTree
70
+ * should compare keys and
87
71
  */
88
72
  constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: RBTreeOptions<K>) {
89
73
  super([], options);
90
74
 
91
- this._root = this._Sentinel;
92
- if (keysOrNodesOrEntries) super.addMany(keysOrNodesOrEntries);
75
+ this._root = this.SENTINEL;
76
+
77
+ if (keysOrNodesOrEntries) {
78
+ this.addMany(keysOrNodesOrEntries);
79
+ }
93
80
  }
94
81
 
95
- protected _Sentinel: NODE = new RedBlackTreeNode<K, V>(NaN as K) as unknown as NODE;
82
+ protected _SENTINEL: NODE = new RedBlackTreeNode<K, V>(NaN as K) as unknown as NODE;
96
83
 
97
84
  /**
98
- * The function returns the value of the `_Sentinel` property.
99
- * @returns The method is returning the value of the `_Sentinel` property.
85
+ * The function returns the value of the _SENTINEL property.
86
+ * @returns The method is returning the value of the `_SENTINEL` property.
100
87
  */
101
- get Sentinel(): NODE {
102
- return this._Sentinel;
88
+ get SENTINEL(): NODE {
89
+ return this._SENTINEL;
103
90
  }
104
91
 
105
- protected _root: NODE;
92
+ protected _root: NODE | undefined;
106
93
 
107
94
  /**
108
- * The function returns the root node.
109
- * @returns The root node of the data structure.
95
+ * The function returns the root node of a tree or undefined if there is no root.
96
+ * @returns The root node of the tree structure, or undefined if there is no root node.
110
97
  */
111
- get root(): NODE {
98
+ get root(): NODE | undefined {
112
99
  return this._root;
113
100
  }
114
101
 
@@ -124,13 +111,13 @@ export class RedBlackTree<
124
111
 
125
112
  /**
126
113
  * The function creates a new Red-Black Tree node with the specified key, value, and color.
127
- * @param {K} key - The key parameter is the key value associated with the node. It is used to
128
- * identify and compare nodes in the Red-Black Tree.
114
+ * @param {K} key - The key parameter represents the key of the node being created. It is of type K,
115
+ * which is a generic type representing the key's data type.
129
116
  * @param {V} [value] - The `value` parameter is an optional parameter that represents the value
130
- * associated with the node. It is of type `V`, which is a generic type that can be replaced with any
131
- * specific type when using the `createNode` method.
117
+ * associated with the key in the node. It is not required and can be omitted if not needed.
132
118
  * @param {RBTNColor} color - The "color" parameter is used to specify the color of the node in a
133
- * Red-Black Tree. It can be either "RED" or "BLACK". By default, the color is set to "BLACK".
119
+ * Red-Black Tree. It is an optional parameter with a default value of "RBTNColor.BLACK". The color
120
+ * can be either "RBTNColor.RED" or "RBTNColor.BLACK".
134
121
  * @returns The method is returning a new instance of a RedBlackTreeNode with the specified key,
135
122
  * value, and color.
136
123
  */
@@ -139,10 +126,10 @@ export class RedBlackTree<
139
126
  }
140
127
 
141
128
  /**
142
- * The function creates a Red-Black Tree with the specified options and returns it.
143
- * @param {RBTreeOptions} [options] - The `options` parameter is an optional object that can be
144
- * passed to the `createTree` function. It is used to customize the behavior of the `RedBlackTree`
145
- * class.
129
+ * The function creates a Red-Black Tree with the given options and returns it.
130
+ * @param [options] - The `options` parameter is an optional object that contains configuration
131
+ * options for creating the Red-Black Tree. It is of type `RBTreeOptions<K>`, where `K` represents
132
+ * the type of keys in the tree.
146
133
  * @returns a new instance of a RedBlackTree object.
147
134
  */
148
135
  override createTree(options?: RBTreeOptions<K>): TREE {
@@ -153,12 +140,19 @@ export class RedBlackTree<
153
140
  }
154
141
 
155
142
  /**
156
- * The function `keyValueOrEntryToNode` takes an keyOrNodeOrEntry and converts it into a node object if possible.
157
- * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry<K, V, NODE>`, where:
158
- * @param {V} [value] - The `value` parameter is an optional value that can be passed to the
159
- * `keyValueOrEntryToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If a value
160
- * is provided, it will be used when creating the new node. If no value is provided, the new node
161
- * @returns a node of type NODE or undefined.
143
+ * Time Complexity: O(1)
144
+ * Space Complexity: O(1)
145
+ */
146
+
147
+ /**
148
+ * Time Complexity: O(1)
149
+ * Space Complexity: O(1)
150
+ *
151
+ * The function `keyValueOrEntryToNode` takes a key, value, or entry and returns a node if it is
152
+ * valid, otherwise it returns undefined.
153
+ * @param {KeyOrNodeOrEntry<K, V, NODE>} keyOrNodeOrEntry - The key, value, or entry to convert.
154
+ * @param {V} [value] - The value associated with the key (if `keyOrNodeOrEntry` is a key).
155
+ * @returns {NODE | undefined} - The corresponding Red-Black Tree node, or `undefined` if conversion fails.
162
156
  */
163
157
  override keyValueOrEntryToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V): NODE | undefined {
164
158
  let node: NODE | undefined;
@@ -183,93 +177,129 @@ export class RedBlackTree<
183
177
  }
184
178
 
185
179
  /**
186
- * The function checks if an keyOrNodeOrEntry is an instance of the RedBlackTreeNode class.
187
- * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry<K, V, NODE>`.
188
- * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the RedBlackTreeNode
189
- * class.
180
+ * Time Complexity: O(1)
181
+ * Space Complexity: O(1)
182
+ * /
183
+
184
+ /**
185
+ * Time Complexity: O(1)
186
+ * Space Complexity: O(1)
187
+ *
188
+ * The function checks if the input is an instance of the RedBlackTreeNode class.
189
+ * @param {KeyOrNodeOrEntry<K, V, NODE>} keyOrNodeOrEntry - The object to check.
190
+ * @returns {boolean} - `true` if the object is a Red-Black Tree node, `false` otherwise.
190
191
  */
191
192
  override isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>): keyOrNodeOrEntry is NODE {
192
193
  return keyOrNodeOrEntry instanceof RedBlackTreeNode;
193
194
  }
194
195
 
195
196
  /**
197
+ * Time Complexity: O(1)
198
+ * Space Complexity: O(1)
199
+ */
200
+
201
+ /**
202
+ * Time Complexity: O(1)
203
+ * Space Complexity: O(1)
204
+ *
196
205
  * The function checks if a given node is a real node in a Red-Black Tree.
197
206
  * @param {NODE | undefined} node - The `node` parameter is of type `NODE | undefined`, which means
198
207
  * it can either be of type `NODE` or `undefined`.
199
208
  * @returns a boolean value.
200
209
  */
201
210
  override isRealNode(node: NODE | undefined): node is NODE {
202
- if (node === this._Sentinel || node === undefined) return false;
211
+ if (node === this._SENTINEL || node === undefined) return false;
203
212
  return node instanceof RedBlackTreeNode;
204
213
  }
205
214
 
206
215
  /**
207
216
  * Time Complexity: O(log n)
208
217
  * Space Complexity: O(1)
209
- * On average (where n is the number of nodes in the tree)
210
218
  */
211
219
 
212
220
  /**
213
221
  * Time Complexity: O(log n)
214
222
  * Space Complexity: O(1)
215
223
  *
216
- * The `add` function adds a new node to a binary search tree and performs necessary rotations and
217
- * color changes to maintain the red-black tree properties.
224
+ * The `getNode` function retrieves a node from a Red-Black Tree based on the provided identifier and
225
+ * callback function.
226
+ * @param {ReturnType<C> | undefined} identifier - The `identifier` parameter is the value or key
227
+ * that you want to search for in the binary search tree. It can be of any type that is compatible
228
+ * with the type of nodes in the tree.
229
+ * @param {C} callback - The `callback` parameter is a function that will be called for each node in
230
+ * the tree. It is used to determine whether a node matches the given identifier. The `callback`
231
+ * function should take a node as its parameter and return a value that can be compared to the
232
+ * `identifier` parameter.
233
+ * @param beginRoot - The `beginRoot` parameter is the starting point for the search in the binary
234
+ * search tree. It can be either a key or a node. If it is a key, it will be converted to a node
235
+ * using the `ensureNode` method. If it is not provided, the `root`
236
+ * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
237
+ * be performed when searching for nodes in the binary search tree. It is an optional parameter and
238
+ * its default value is taken from the `iterationType` property of the class.
239
+ * @returns The method is returning a value of type `NODE | null | undefined`.
240
+ */
241
+ override getNode<C extends BTNCallback<NODE>>(
242
+ identifier: ReturnType<C> | undefined,
243
+ callback: C = this._defaultOneParamCallback as C,
244
+ beginRoot: BSTNKeyOrNode<K, NODE> = this.root,
245
+ iterationType = this.iterationType
246
+ ): NODE | null | undefined {
247
+ if ((identifier as any) instanceof RedBlackTreeNode) callback = (node => node) as C;
248
+ beginRoot = this.ensureNode(beginRoot);
249
+ return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
250
+ }
251
+
252
+ /**
253
+ * Time Complexity: O(1)
254
+ * Space Complexity: O(1)
255
+ */
256
+
257
+ /**
258
+ * Time Complexity: O(1)
259
+ * Space Complexity: O(1)
260
+ *
261
+ * The "clear" function sets the root node of a data structure to a sentinel value and resets the
262
+ * size counter to zero.
263
+ */
264
+ override clear() {
265
+ this._root = this.SENTINEL;
266
+ this._size = 0;
267
+ }
268
+
269
+ /**
270
+ * Time Complexity: O(log n)
271
+ * Space Complexity: O(1)
272
+ */
273
+
274
+ /**
275
+ * Time Complexity: O(log n)
276
+ * Space Complexity: O(1)
277
+ *
278
+ * The function adds a new node to a Red-Black Tree data structure and returns a boolean indicating
279
+ * whether the operation was successful.
218
280
  * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be either a key, a node, or an
219
281
  * entry.
220
- * @param {V} [value] - The `value` parameter represents the value associated with the key that is
221
- * being added to the binary search tree.
222
- * @returns The method `add` returns either the newly added node (`NODE`) or `undefined`.
282
+ * @param {V} [value] - The `value` parameter is the value associated with the key that is being
283
+ * added to the tree.
284
+ * @returns The method is returning a boolean value. It returns true if the node was successfully
285
+ * added or updated, and false otherwise.
223
286
  */
224
287
  override add(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V): boolean {
225
288
  const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value);
226
- if (newNode === undefined) return false;
289
+ if (!this.isRealNode(newNode)) return false;
227
290
 
228
- newNode.left = this._Sentinel;
229
- newNode.right = this._Sentinel;
291
+ const insertStatus = this._insert(newNode);
230
292
 
231
- let y: NODE | undefined = undefined;
232
- let x: NODE | undefined = this.root;
233
-
234
- while (x !== this._Sentinel) {
235
- y = x;
236
- if (x) {
237
- if (newNode.key < x.key) {
238
- x = x.left;
239
- } else if (newNode.key > x.key) {
240
- x = x?.right;
241
- } else {
242
- if (newNode !== x) {
243
- this._replaceNode(x, newNode);
244
- }
245
- return false;
246
- }
293
+ if (insertStatus === 'inserted') {
294
+ // Ensure the root is black
295
+ if (this.isRealNode(this._root)) {
296
+ this._root.color = RBTNColor.BLACK;
297
+ } else {
298
+ return false;
247
299
  }
248
- }
249
-
250
- newNode.parent = y;
251
- if (y === undefined) {
252
- this._setRoot(newNode);
253
- } else if (newNode.key < y.key) {
254
- y.left = newNode;
255
- } else {
256
- y.right = newNode;
257
- }
258
-
259
- if (newNode.parent === undefined) {
260
- newNode.color = RBTNColor.BLACK;
261
- this._size++;
262
- return false;
263
- }
264
-
265
- if (newNode.parent.parent === undefined) {
266
300
  this._size++;
267
- return false;
268
- }
269
-
270
- this._fixInsert(newNode);
271
- this._size++;
272
- return true;
301
+ return true;
302
+ } else return insertStatus === 'updated';
273
303
  }
274
304
 
275
305
  /**
@@ -281,113 +311,88 @@ export class RedBlackTree<
281
311
  * Time Complexity: O(log n)
282
312
  * Space Complexity: O(1)
283
313
  *
284
- * The `delete` function removes a node from a binary tree based on a given identifier and updates
285
- * the tree accordingly.
286
- * @param {ReturnType<C> | null | undefined} identifier - The `identifier` parameter is the value
287
- * that you want to use to identify the node that you want to delete from the binary tree. It can be
288
- * of any type that is returned by the callback function `C`. It can also be `null` or `undefined` if
289
- * you don't want to
290
- * @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` and
291
- * returns a value of type `ReturnType<C>`. It is used to determine if a node should be deleted based
292
- * on its identifier. The `callback` function is optional and defaults to `this._defaultOneParam
293
- * @returns an array of `BinaryTreeDeleteResult<NODE>`.
294
- */
295
- delete<C extends BTNCallback<NODE>>(
314
+ * The function `delete` in a binary tree class deletes a node from the tree and fixes the tree if
315
+ * necessary.
316
+ * @param {ReturnType<C> | null | undefined} identifier - The `identifier` parameter is the
317
+ * identifier of the node that needs to be deleted from the binary tree. It can be of any type that
318
+ * is returned by the callback function `C`. It can also be `null` or `undefined` if the node to be
319
+ * deleted is not found.
320
+ * @param {C} callback - The `callback` parameter is a function that is used to retrieve a node from
321
+ * the binary tree based on its identifier. It is an optional parameter and if not provided, the
322
+ * `_defaultOneParamCallback` function is used as the default callback. The callback function should
323
+ * return the identifier of the node to
324
+ * @returns an array of BinaryTreeDeleteResult<NODE> objects.
325
+ */
326
+ override delete<C extends BTNCallback<NODE>>(
296
327
  identifier: ReturnType<C> | null | undefined,
297
328
  callback: C = this._defaultOneParamCallback as C
298
329
  ): BinaryTreeDeleteResult<NODE>[] {
299
- const ans: BinaryTreeDeleteResult<NODE>[] = [];
300
- if (identifier === null) return ans;
301
- const helper = (node: NODE | undefined): void => {
302
- let z: NODE = this._Sentinel;
303
- let x: NODE | undefined, y: NODE;
304
- while (node !== this._Sentinel) {
305
- if (node && callback(node) === identifier) {
306
- z = node;
307
- }
330
+ if (identifier === null) return [];
331
+ const results: BinaryTreeDeleteResult<NODE>[] = [];
308
332
 
309
- if (node && identifier && callback(node) <= identifier) {
310
- node = node.right;
311
- } else {
312
- node = node?.left;
313
- }
314
- }
333
+ const nodeToDelete = this.isRealNode(identifier) ? identifier : this.getNode(identifier, callback);
315
334
 
316
- if (z === this._Sentinel) {
317
- this._size--;
318
- return;
319
- }
335
+ if (!nodeToDelete) {
336
+ return results;
337
+ }
320
338
 
321
- y = z;
322
- let yOriginalColor: number = y.color;
323
- if (z.left === this._Sentinel) {
324
- x = z.right;
325
- this._rbTransplant(z, z.right!);
326
- } else if (z.right === this._Sentinel) {
327
- x = z.left;
328
- this._rbTransplant(z, z.left!);
329
- } else {
330
- y = this.getLeftMost(z.right)!;
331
- yOriginalColor = y.color;
332
- x = y.right;
333
- if (y.parent === z) {
334
- x!.parent = y;
339
+ let originalColor = nodeToDelete.color;
340
+ let replacementNode: NODE | undefined;
341
+
342
+ if (!this.isRealNode(nodeToDelete.left)) {
343
+ replacementNode = nodeToDelete.right;
344
+ this._transplant(nodeToDelete, nodeToDelete.right);
345
+ } else if (!this.isRealNode(nodeToDelete.right)) {
346
+ replacementNode = nodeToDelete.left;
347
+ this._transplant(nodeToDelete, nodeToDelete.left);
348
+ } else {
349
+ const successor = this.getLeftMost(nodeToDelete.right);
350
+ if (successor) {
351
+ originalColor = successor.color;
352
+ replacementNode = successor.right;
353
+
354
+ if (successor.parent === nodeToDelete) {
355
+ if (this.isRealNode(replacementNode)) {
356
+ replacementNode.parent = successor;
357
+ }
335
358
  } else {
336
- this._rbTransplant(y, y.right!);
337
- y.right = z.right;
338
- y.right!.parent = y;
359
+ this._transplant(successor, successor.right);
360
+ successor.right = nodeToDelete.right;
361
+ if (this.isRealNode(successor.right)) {
362
+ successor.right.parent = successor;
363
+ }
339
364
  }
340
365
 
341
- this._rbTransplant(z, y);
342
- y.left = z.left;
343
- y.left!.parent = y;
344
- y.color = z.color;
345
- }
346
- if (yOriginalColor === RBTNColor.BLACK) {
347
- this._fixDelete(x!);
366
+ this._transplant(nodeToDelete, successor);
367
+ successor.left = nodeToDelete.left;
368
+ if (this.isRealNode(successor.left)) {
369
+ successor.left.parent = successor;
370
+ }
371
+ successor.color = nodeToDelete.color;
348
372
  }
349
- this._size--;
350
- ans.push({ deleted: z, needBalanced: undefined });
351
- };
352
- helper(this.root);
353
- return ans;
373
+ }
374
+ this._size--;
375
+
376
+ // If the original color was black, fix the tree
377
+ if (originalColor === RBTNColor.BLACK) {
378
+ this._deleteFixup(replacementNode);
379
+ }
380
+
381
+ results.push({ deleted: nodeToDelete, needBalanced: undefined });
382
+
383
+ return results;
354
384
  }
355
385
 
356
386
  /**
357
- * Time Complexity: O(log n)
358
- * Space Complexity: O(1)
387
+ * The function sets the root of a tree-like structure and updates the parent property of the new
388
+ * root.
389
+ * @param {NODE | undefined} v - v is a parameter of type NODE or undefined.
359
390
  */
360
-
361
- /**
362
- * Time Complexity: O(log n)
363
- * Space Complexity: O(1)
364
- *
365
- * The function `getNode` retrieves a single node from a binary tree based on a given identifier and
366
- * callback function.
367
- * @param {ReturnType<C> | undefined} identifier - The `identifier` parameter is the value used to
368
- * identify the node you want to retrieve. It can be of any type that is the return type of the `C`
369
- * callback function. If the `identifier` is `undefined`, it means you want to retrieve the first
370
- * node that matches the other criteria
371
- * @param {C} callback - The `callback` parameter is a function that will be called for each node in
372
- * the binary tree. It is used to determine if a node matches the given identifier. The `callback`
373
- * function should take a single parameter of type `NODE` (the type of the nodes in the binary tree) and
374
- * @param {K | NODE | undefined} beginRoot - The `beginRoot` parameter is the starting point for
375
- * searching for a node in a binary tree. It can be either a key value or a node object. If it is not
376
- * provided, the search will start from the root of the binary tree.
377
- * @param iterationType - The `iterationType` parameter is a variable that determines the type of
378
- * iteration to be performed when searching for nodes in the binary tree. It is used in the
379
- * `getNodes` method, which is called within the `getNode` method.
380
- * @returns a value of type `NODE`, `null`, or `undefined`.
381
- */
382
- getNode<C extends BTNCallback<NODE>>(
383
- identifier: ReturnType<C> | undefined,
384
- callback: C = this._defaultOneParamCallback as C,
385
- beginRoot: BSTNKeyOrNode<K, NODE> = this.root,
386
- iterationType = this.iterationType
387
- ): NODE | null | undefined {
388
- if ((identifier as any) instanceof RedBlackTreeNode) callback = (node => node) as C;
389
- beginRoot = this.ensureNode(beginRoot);
390
- return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? undefined;
391
+ protected override _setRoot(v: NODE | undefined) {
392
+ if (v) {
393
+ v.parent = undefined;
394
+ }
395
+ this._root = v;
391
396
  }
392
397
 
393
398
  /**
@@ -399,11 +404,18 @@ export class RedBlackTree<
399
404
  * Time Complexity: O(1)
400
405
  * Space Complexity: O(1)
401
406
  *
402
- * The "clear" function sets the root node to the sentinel node and resets the size to 0.
407
+ * The function replaces an old node with a new node while preserving the color of the old node.
408
+ * @param {NODE} oldNode - The `oldNode` parameter represents the node that needs to be replaced in
409
+ * the data structure.
410
+ * @param {NODE} newNode - The `newNode` parameter is the new node that will replace the old node in
411
+ * the data structure.
412
+ * @returns The method is returning the result of calling the `_replaceNode` method from the
413
+ * superclass, with the `oldNode` and `newNode` parameters.
403
414
  */
404
- override clear() {
405
- this._root = this._Sentinel;
406
- this._size = 0;
415
+ protected override _replaceNode(oldNode: NODE, newNode: NODE): NODE {
416
+ newNode.color = oldNode.color;
417
+
418
+ return super._replaceNode(oldNode, newNode);
407
419
  }
408
420
 
409
421
  /**
@@ -415,36 +427,45 @@ export class RedBlackTree<
415
427
  * Time Complexity: O(log n)
416
428
  * Space Complexity: O(1)
417
429
  *
418
- * The function returns the predecessor of a given node in a red-black tree.
419
- * @param {RedBlackTreeNode} x - The parameter `x` is of type `RedBlackTreeNode`, which represents a node in a
420
- * Red-Black Tree.
421
- * @returns the predecessor of the given RedBlackTreeNode 'x'.
422
- */
423
- override getPredecessor(x: NODE): NODE {
424
- if (this.isRealNode(x.left)) {
425
- return this.getRightMost(x.left)!;
430
+ * The `_insert` function inserts or updates a node in a binary search tree and performs necessary
431
+ * fix-ups to maintain the red-black tree properties.
432
+ * @param {NODE} node - The `node` parameter represents the node that needs to be inserted into a
433
+ * binary search tree. It contains a `key` property that is used to determine the position of the
434
+ * node in the tree.
435
+ * @returns {'inserted' | 'updated'} - The result of the insertion.
436
+ */
437
+ protected _insert(node: NODE): 'inserted' | 'updated' {
438
+ let current = this.root;
439
+ let parent: NODE | undefined = undefined;
440
+
441
+ while (this.isRealNode(current)) {
442
+ parent = current;
443
+ if (node.key < current.key) {
444
+ current = current.left ?? this.SENTINEL;
445
+ } else if (node.key > current.key) {
446
+ current = current.right ?? this.SENTINEL;
447
+ } else {
448
+ this._replaceNode(current, node);
449
+ return 'updated';
450
+ }
426
451
  }
427
452
 
428
- let y: NODE | undefined = x.parent;
429
- while (this.isRealNode(y) && x === y.left) {
430
- x = y!;
431
- y = y!.parent;
453
+ node.parent = parent;
454
+
455
+ if (!parent) {
456
+ this._setRoot(node);
457
+ } else if (node.key < parent.key) {
458
+ parent.left = node;
459
+ } else {
460
+ parent.right = node;
432
461
  }
433
462
 
434
- return y!;
435
- }
463
+ node.left = this.SENTINEL;
464
+ node.right = this.SENTINEL;
465
+ node.color = RBTNColor.RED;
436
466
 
437
- /**
438
- * The function sets the root node of a tree structure and updates the parent property of the new
439
- * root node.
440
- * @param {NODE} v - The parameter "v" is of type "NODE", which represents a node in a data
441
- * structure.
442
- */
443
- protected override _setRoot(v: NODE) {
444
- if (v) {
445
- v.parent = undefined;
446
- }
447
- this._root = v;
467
+ this._insertFixup(node);
468
+ return 'inserted';
448
469
  }
449
470
 
450
471
  /**
@@ -456,59 +477,22 @@ export class RedBlackTree<
456
477
  * Time Complexity: O(1)
457
478
  * Space Complexity: O(1)
458
479
  *
459
- * The function performs a left rotation on a binary tree node.
460
- * @param {RedBlackTreeNode} x - The parameter `x` is of type `NODE`, which likely represents a node in a binary tree.
461
- */
462
- protected _leftRotate(x: NODE): void {
463
- if (x.right) {
464
- const y: NODE = x.right;
465
- x.right = y.left;
466
- if (y.left !== this._Sentinel) {
467
- if (y.left) y.left.parent = x;
468
- }
469
- y.parent = x.parent;
470
- if (x.parent === undefined) {
471
- this._setRoot(y);
472
- } else if (x === x.parent.left) {
473
- x.parent.left = y;
474
- } else {
475
- x.parent.right = y;
476
- }
477
- y.left = x;
478
- x.parent = y;
479
- }
480
- }
481
-
482
- /**
483
- * Time Complexity: O(1)
484
- * Space Complexity: O(1)
480
+ * The function `_transplant` is used to replace a node `u` with another node `v` in a binary tree.
481
+ * @param {NODE} u - The parameter "u" represents a node in a binary tree.
482
+ * @param {NODE | undefined} v - The parameter `v` is of type `NODE | undefined`, which means it can
483
+ * either be a `NODE` object or `undefined`.
485
484
  */
485
+ protected _transplant(u: NODE, v: NODE | undefined): void {
486
+ if (!u.parent) {
487
+ this._setRoot(v);
488
+ } else if (u === u.parent.left) {
489
+ u.parent.left = v;
490
+ } else {
491
+ u.parent.right = v;
492
+ }
486
493
 
487
- /**
488
- * Time Complexity: O(1)
489
- * Space Complexity: O(1)
490
- *
491
- * The function performs a right rotation on a red-black tree node.
492
- * @param {RedBlackTreeNode} x - x is a RedBlackTreeNode, which represents the node that needs to be right
493
- * rotated.
494
- */
495
- protected _rightRotate(x: NODE): void {
496
- if (x.left) {
497
- const y: NODE = x.left;
498
- x.left = y.right;
499
- if (y.right !== this._Sentinel) {
500
- if (y.right) y.right.parent = x;
501
- }
502
- y.parent = x.parent;
503
- if (x.parent === undefined) {
504
- this._setRoot(y);
505
- } else if (x === x.parent.right) {
506
- x.parent.right = y;
507
- } else {
508
- x.parent.left = y;
509
- }
510
- y.right = x;
511
- x.parent = y;
494
+ if (v) {
495
+ v.parent = u.parent;
512
496
  }
513
497
  }
514
498
 
@@ -521,64 +505,66 @@ export class RedBlackTree<
521
505
  * Time Complexity: O(log n)
522
506
  * Space Complexity: O(1)
523
507
  *
524
- * The `_fixInsert` function is used to fix the red-black tree after an insertion operation.
525
- * @param {RedBlackTreeNode} k - The parameter `k` is a RedBlackTreeNode object, which represents a node in a
526
- * red-black tree.
527
- */
528
- protected _fixInsert(k: NODE): void {
529
- let u: NODE | undefined;
530
- while (k.parent && k.parent.color === RBTNColor.RED) {
531
- if (k.parent.parent && k.parent === k.parent.parent.right) {
532
- u = k.parent.parent.left;
533
-
534
- if (u && u.color === RBTNColor.RED) {
535
- // Delay color flip
536
- k.parent.color = RBTNColor.BLACK;
537
- u.color = RBTNColor.BLACK;
538
- k.parent.parent.color = RBTNColor.RED;
539
- k = k.parent.parent;
508
+ * The `_insertFixup` function is used to fix the Red-Black Tree after inserting a new node.
509
+ * @param {NODE | undefined} z - The parameter `z` represents a node in the Red-Black Tree. It can
510
+ * either be a valid node object or `undefined`.
511
+ */
512
+ protected _insertFixup(z: NODE | undefined): void {
513
+ // Continue fixing the tree as long as the parent of z is red
514
+ while (z?.parent?.color === RBTNColor.RED) {
515
+ // Check if the parent of z is the left child of its parent
516
+ if (z.parent === z.parent.parent?.left) {
517
+ // Case 1: The uncle (y) of z is red
518
+ const y = z.parent.parent.right;
519
+ if (y?.color === RBTNColor.RED) {
520
+ // Set colors to restore properties of Red-Black Tree
521
+ z.parent.color = RBTNColor.BLACK;
522
+ y.color = RBTNColor.BLACK;
523
+ z.parent.parent.color = RBTNColor.RED;
524
+ // Move up the tree to continue fixing
525
+ z = z.parent.parent;
540
526
  } else {
541
- if (k === k.parent.left) {
542
- k = k.parent;
543
- this._rightRotate(k);
527
+ // Case 2: The uncle (y) of z is black, and z is a right child
528
+ if (z === z.parent.right) {
529
+ // Perform a left rotation to transform the case into Case 3
530
+ z = z.parent;
531
+ this._leftRotate(z);
544
532
  }
545
533
 
546
- // Check color before rotation
547
- if (k.parent!.color === RBTNColor.RED) {
548
- k.parent!.color = RBTNColor.BLACK;
549
- k.parent!.parent!.color = RBTNColor.RED;
534
+ // Case 3: The uncle (y) of z is black, and z is a left child
535
+ // Adjust colors and perform a right rotation
536
+ if (z && this.isRealNode(z.parent) && this.isRealNode(z.parent.parent)) {
537
+ z.parent.color = RBTNColor.BLACK;
538
+ z.parent.parent.color = RBTNColor.RED;
539
+ this._rightRotate(z.parent.parent);
550
540
  }
551
- this._leftRotate(k.parent!.parent!);
552
541
  }
553
542
  } else {
554
- u = k.parent!.parent!.right;
555
-
556
- if (u && u.color === RBTNColor.RED) {
557
- // Delay color flip
558
- k.parent.color = RBTNColor.BLACK;
559
- u.color = RBTNColor.BLACK;
560
- k.parent.parent!.color = RBTNColor.RED;
561
- k = k.parent.parent!;
543
+ // Symmetric case for the right child (left and right exchanged)
544
+ // Follow the same logic as above with left and right exchanged
545
+ const y: NODE | undefined = z?.parent?.parent?.left;
546
+ if (y?.color === RBTNColor.RED) {
547
+ z.parent.color = RBTNColor.BLACK;
548
+ y.color = RBTNColor.BLACK;
549
+ z.parent.parent!.color = RBTNColor.RED;
550
+ z = z.parent.parent;
562
551
  } else {
563
- if (k === k.parent.right) {
564
- k = k.parent;
565
- this._leftRotate(k);
552
+ if (z === z.parent.left) {
553
+ z = z.parent;
554
+ this._rightRotate(z);
566
555
  }
567
556
 
568
- // Check color before rotation
569
- if (k.parent!.color === RBTNColor.RED) {
570
- k.parent!.color = RBTNColor.BLACK;
571
- k.parent!.parent!.color = RBTNColor.RED;
557
+ if (z && this.isRealNode(z.parent) && this.isRealNode(z.parent.parent)) {
558
+ z.parent.color = RBTNColor.BLACK;
559
+ z.parent.parent.color = RBTNColor.RED;
560
+ this._leftRotate(z.parent.parent);
572
561
  }
573
- this._rightRotate(k.parent!.parent!);
574
562
  }
575
563
  }
576
-
577
- if (k === this.root) {
578
- break;
579
- }
580
564
  }
581
- this.root.color = RBTNColor.BLACK;
565
+
566
+ // Ensure that the root is black after fixing
567
+ if (this.isRealNode(this._root)) this._root.color = RBTNColor.BLACK;
582
568
  }
583
569
 
584
570
  /**
@@ -590,67 +576,82 @@ export class RedBlackTree<
590
576
  * Time Complexity: O(log n)
591
577
  * Space Complexity: O(1)
592
578
  *
593
- * The function `_fixDelete` is used to fix the red-black tree after a node deletion.
594
- * @param {RedBlackTreeNode} x - The parameter `x` represents a node in a Red-Black Tree (RBT).
595
- */
596
- protected _fixDelete(x: NODE): void {
597
- let s: NODE | undefined;
598
- while (x !== this.root && x.color === RBTNColor.BLACK) {
599
- if (x.parent && x === x.parent.left) {
600
- s = x.parent.right!;
601
- if (s.color === 1) {
602
- s.color = RBTNColor.BLACK;
603
- x.parent.color = RBTNColor.RED;
604
- this._leftRotate(x.parent);
605
- s = x.parent.right!;
579
+ * The `_deleteFixup` function is used to fix the red-black tree after a node deletion by adjusting
580
+ * the colors and performing rotations.
581
+ * @param {NODE | undefined} node - The `node` parameter represents a node in a Red-Black Tree data
582
+ * structure. It can be either a valid node object or `undefined`.
583
+ * @returns The function does not return any value. It has a return type of `void`.
584
+ */
585
+ protected _deleteFixup(node: NODE | undefined): void {
586
+ // Early exit condition
587
+ if (!node || node === this.root || node.color === RBTNColor.BLACK) {
588
+ if (node) {
589
+ node.color = RBTNColor.BLACK; // Ensure the final node is black
590
+ }
591
+ return;
592
+ }
593
+
594
+ while (node && node !== this.root && node.color === RBTNColor.BLACK) {
595
+ const parent: NODE | undefined = node.parent;
596
+
597
+ if (!parent) {
598
+ break; // Ensure the loop terminates if there's an issue with the tree structure
599
+ }
600
+
601
+ if (node === parent.left) {
602
+ let sibling = parent.right;
603
+
604
+ // Cases 1 and 2: Sibling is red or both children of sibling are black
605
+ if (sibling?.color === RBTNColor.RED) {
606
+ sibling.color = RBTNColor.BLACK;
607
+ parent.color = RBTNColor.RED;
608
+ this._leftRotate(parent);
609
+ sibling = parent.right;
606
610
  }
607
611
 
608
- if (s.left !== undefined && s.left.color === RBTNColor.BLACK && s.right && s.right.color === RBTNColor.BLACK) {
609
- s.color = RBTNColor.RED;
610
- x = x.parent;
612
+ // Case 3: Sibling's left child is black
613
+ if ((sibling?.left?.color ?? RBTNColor.BLACK) === RBTNColor.BLACK) {
614
+ if (sibling) sibling.color = RBTNColor.RED;
615
+ node = parent;
611
616
  } else {
612
- if (s.right && s.right.color === RBTNColor.BLACK) {
613
- if (s.left) s.left.color = RBTNColor.BLACK;
614
- s.color = RBTNColor.RED;
615
- this._rightRotate(s);
616
- s = x.parent.right;
617
- }
618
-
619
- if (s) s.color = x.parent.color;
620
- x.parent.color = RBTNColor.BLACK;
621
- if (s && s.right) s.right.color = RBTNColor.BLACK;
622
- this._leftRotate(x.parent);
623
- x = this.root;
617
+ // Case 4: Adjust colors and perform a right rotation
618
+ if (sibling?.left) sibling.left.color = RBTNColor.BLACK;
619
+ if (sibling) sibling.color = parent.color;
620
+ parent.color = RBTNColor.BLACK;
621
+ this._rightRotate(parent);
622
+ node = this.root;
624
623
  }
625
624
  } else {
626
- s = x.parent!.left!;
627
- if (s.color === 1) {
628
- s.color = RBTNColor.BLACK;
629
- x.parent!.color = RBTNColor.RED;
630
- this._rightRotate(x.parent!);
631
- s = x.parent!.left;
625
+ // Symmetric case for the right child (left and right exchanged)
626
+ let sibling = parent.left;
627
+
628
+ // Cases 1 and 2: Sibling is red or both children of sibling are black
629
+ if (sibling?.color === RBTNColor.RED) {
630
+ sibling.color = RBTNColor.BLACK;
631
+ if (parent) parent.color = RBTNColor.RED;
632
+ this._rightRotate(parent);
633
+ if (parent) sibling = parent.left;
632
634
  }
633
635
 
634
- if (s && s.right && s.right.color === RBTNColor.BLACK && s.right.color === RBTNColor.BLACK) {
635
- s.color = RBTNColor.RED;
636
- x = x.parent!;
636
+ // Case 3: Sibling's left child is black
637
+ if ((sibling?.right?.color ?? RBTNColor.BLACK) === RBTNColor.BLACK) {
638
+ if (sibling) sibling.color = RBTNColor.RED;
639
+ node = parent;
637
640
  } else {
638
- if (s && s.left && s.left.color === RBTNColor.BLACK) {
639
- if (s.right) s.right.color = RBTNColor.BLACK;
640
- s.color = RBTNColor.RED;
641
- this._leftRotate(s);
642
- s = x.parent!.left;
643
- }
644
-
645
- if (s) s.color = x.parent!.color;
646
- x.parent!.color = RBTNColor.BLACK;
647
- if (s && s.left) s.left.color = RBTNColor.BLACK;
648
- this._rightRotate(x.parent!);
649
- x = this.root;
641
+ // Case 4: Adjust colors and perform a left rotation
642
+ if (sibling?.right) sibling.right.color = RBTNColor.BLACK;
643
+ if (sibling) sibling.color = parent.color;
644
+ if (parent) parent.color = RBTNColor.BLACK;
645
+ this._leftRotate(parent);
646
+ node = this.root;
650
647
  }
651
648
  }
652
649
  }
653
- x.color = RBTNColor.BLACK;
650
+
651
+ // Ensure that the final node (possibly the root) is black
652
+ if (node) {
653
+ node.color = RBTNColor.BLACK;
654
+ }
654
655
  }
655
656
 
656
657
  /**
@@ -662,33 +663,74 @@ export class RedBlackTree<
662
663
  * Time Complexity: O(1)
663
664
  * Space Complexity: O(1)
664
665
  *
665
- * The function `_rbTransplant` replaces one node in a red-black tree with another node.
666
- * @param {RedBlackTreeNode} u - The parameter "u" represents a RedBlackTreeNode object.
667
- * @param {RedBlackTreeNode} v - The parameter "v" is a RedBlackTreeNode object.
666
+ * The `_leftRotate` function performs a left rotation on a given node in a binary tree.
667
+ * @param {NODE | undefined} x - The parameter `x` is of type `NODE | undefined`. It represents a
668
+ * node in a binary tree or `undefined` if there is no node.
669
+ * @returns void, which means it does not return any value.
668
670
  */
669
- protected _rbTransplant(u: NODE, v: NODE): void {
670
- if (u.parent === undefined) {
671
- this._setRoot(v);
672
- } else if (u === u.parent.left) {
673
- u.parent.left = v;
671
+ protected _leftRotate(x: NODE | undefined): void {
672
+ if (!x || !x.right) {
673
+ return;
674
+ }
675
+
676
+ const y = x.right;
677
+ x.right = y.left;
678
+
679
+ if (this.isRealNode(y.left)) {
680
+ y.left.parent = x;
681
+ }
682
+
683
+ y.parent = x.parent;
684
+
685
+ if (!x.parent) {
686
+ this._setRoot(y);
687
+ } else if (x === x.parent.left) {
688
+ x.parent.left = y;
674
689
  } else {
675
- u.parent.right = v;
690
+ x.parent.right = y;
676
691
  }
677
- v.parent = u.parent;
692
+
693
+ y.left = x;
694
+ x.parent = y;
678
695
  }
679
696
 
680
697
  /**
681
- * The function replaces an old node with a new node while preserving the color of the old node.
682
- * @param {NODE} oldNode - The `oldNode` parameter represents the node that needs to be replaced in a
683
- * data structure. It is of type `NODE`, which is the type of the nodes in the data structure.
684
- * @param {NODE} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the
685
- * data structure.
686
- * @returns The method is returning the result of calling the `_replaceNode` method from the
687
- * superclass, passing in the `oldNode` and `newNode` as arguments.
698
+ * Time Complexity: O(1)
699
+ * Space Complexity: O(1)
688
700
  */
689
- protected _replaceNode(oldNode: NODE, newNode: NODE): NODE {
690
- newNode.color = oldNode.color;
691
701
 
692
- return super._replaceNode(oldNode, newNode);
702
+ /**
703
+ * Time Complexity: O(1)
704
+ * Space Complexity: O(1)
705
+ *
706
+ * The `_rightRotate` function performs a right rotation on a given node in a binary tree.
707
+ * @param {NODE | undefined} y - The parameter `y` is of type `NODE | undefined`. It represents a
708
+ * node in a binary tree or `undefined` if there is no node.
709
+ * @returns void, which means it does not return any value.
710
+ */
711
+ protected _rightRotate(y: NODE | undefined): void {
712
+ if (!y || !y.left) {
713
+ return;
714
+ }
715
+
716
+ const x = y.left;
717
+ y.left = x.right;
718
+
719
+ if (this.isRealNode(x.right)) {
720
+ x.right.parent = y;
721
+ }
722
+
723
+ x.parent = y.parent;
724
+
725
+ if (!y.parent) {
726
+ this._setRoot(x);
727
+ } else if (y === y.parent.left) {
728
+ y.parent.left = x;
729
+ } else {
730
+ y.parent.right = x;
731
+ }
732
+
733
+ x.right = y;
734
+ y.parent = x;
693
735
  }
694
736
  }