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