queue-typed 2.0.5 → 2.1.0

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 (102) hide show
  1. package/README.md +1 -1
  2. package/dist/data-structures/base/iterable-element-base.d.ts +186 -83
  3. package/dist/data-structures/base/iterable-element-base.js +149 -107
  4. package/dist/data-structures/base/iterable-entry-base.d.ts +95 -119
  5. package/dist/data-structures/base/iterable-entry-base.js +59 -116
  6. package/dist/data-structures/base/linear-base.d.ts +250 -192
  7. package/dist/data-structures/base/linear-base.js +137 -274
  8. package/dist/data-structures/binary-tree/avl-tree-counter.d.ts +126 -158
  9. package/dist/data-structures/binary-tree/avl-tree-counter.js +171 -205
  10. package/dist/data-structures/binary-tree/avl-tree-multi-map.d.ts +100 -69
  11. package/dist/data-structures/binary-tree/avl-tree-multi-map.js +135 -87
  12. package/dist/data-structures/binary-tree/avl-tree.d.ts +138 -149
  13. package/dist/data-structures/binary-tree/avl-tree.js +208 -195
  14. package/dist/data-structures/binary-tree/binary-tree.d.ts +476 -632
  15. package/dist/data-structures/binary-tree/binary-tree.js +598 -869
  16. package/dist/data-structures/binary-tree/bst.d.ts +258 -306
  17. package/dist/data-structures/binary-tree/bst.js +505 -481
  18. package/dist/data-structures/binary-tree/red-black-tree.d.ts +107 -179
  19. package/dist/data-structures/binary-tree/red-black-tree.js +114 -209
  20. package/dist/data-structures/binary-tree/tree-counter.d.ts +132 -154
  21. package/dist/data-structures/binary-tree/tree-counter.js +172 -203
  22. package/dist/data-structures/binary-tree/tree-multi-map.d.ts +72 -69
  23. package/dist/data-structures/binary-tree/tree-multi-map.js +105 -85
  24. package/dist/data-structures/graph/abstract-graph.d.ts +238 -233
  25. package/dist/data-structures/graph/abstract-graph.js +267 -237
  26. package/dist/data-structures/graph/directed-graph.d.ts +108 -224
  27. package/dist/data-structures/graph/directed-graph.js +146 -233
  28. package/dist/data-structures/graph/map-graph.d.ts +49 -55
  29. package/dist/data-structures/graph/map-graph.js +56 -59
  30. package/dist/data-structures/graph/undirected-graph.d.ts +103 -146
  31. package/dist/data-structures/graph/undirected-graph.js +129 -149
  32. package/dist/data-structures/hash/hash-map.d.ts +164 -338
  33. package/dist/data-structures/hash/hash-map.js +270 -457
  34. package/dist/data-structures/heap/heap.d.ts +214 -289
  35. package/dist/data-structures/heap/heap.js +340 -349
  36. package/dist/data-structures/heap/max-heap.d.ts +11 -47
  37. package/dist/data-structures/heap/max-heap.js +11 -66
  38. package/dist/data-structures/heap/min-heap.d.ts +12 -47
  39. package/dist/data-structures/heap/min-heap.js +11 -66
  40. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +231 -347
  41. package/dist/data-structures/linked-list/doubly-linked-list.js +368 -494
  42. package/dist/data-structures/linked-list/singly-linked-list.d.ts +261 -310
  43. package/dist/data-structures/linked-list/singly-linked-list.js +447 -466
  44. package/dist/data-structures/linked-list/skip-linked-list.d.ts +0 -107
  45. package/dist/data-structures/linked-list/skip-linked-list.js +0 -100
  46. package/dist/data-structures/priority-queue/max-priority-queue.d.ts +12 -56
  47. package/dist/data-structures/priority-queue/max-priority-queue.js +11 -78
  48. package/dist/data-structures/priority-queue/min-priority-queue.d.ts +11 -57
  49. package/dist/data-structures/priority-queue/min-priority-queue.js +10 -79
  50. package/dist/data-structures/priority-queue/priority-queue.d.ts +2 -61
  51. package/dist/data-structures/priority-queue/priority-queue.js +8 -83
  52. package/dist/data-structures/queue/deque.d.ts +227 -254
  53. package/dist/data-structures/queue/deque.js +309 -348
  54. package/dist/data-structures/queue/queue.d.ts +180 -201
  55. package/dist/data-structures/queue/queue.js +265 -248
  56. package/dist/data-structures/stack/stack.d.ts +124 -102
  57. package/dist/data-structures/stack/stack.js +181 -125
  58. package/dist/data-structures/trie/trie.d.ts +164 -165
  59. package/dist/data-structures/trie/trie.js +189 -172
  60. package/dist/interfaces/binary-tree.d.ts +56 -6
  61. package/dist/interfaces/graph.d.ts +16 -0
  62. package/dist/types/data-structures/base/base.d.ts +1 -1
  63. package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -0
  64. package/dist/types/utils/utils.d.ts +1 -0
  65. package/dist/utils/utils.d.ts +1 -1
  66. package/dist/utils/utils.js +2 -1
  67. package/package.json +2 -2
  68. package/src/data-structures/base/iterable-element-base.ts +238 -115
  69. package/src/data-structures/base/iterable-entry-base.ts +96 -120
  70. package/src/data-structures/base/linear-base.ts +271 -277
  71. package/src/data-structures/binary-tree/avl-tree-counter.ts +198 -216
  72. package/src/data-structures/binary-tree/avl-tree-multi-map.ts +192 -101
  73. package/src/data-structures/binary-tree/avl-tree.ts +239 -206
  74. package/src/data-structures/binary-tree/binary-tree.ts +664 -893
  75. package/src/data-structures/binary-tree/bst.ts +568 -570
  76. package/src/data-structures/binary-tree/red-black-tree.ts +161 -222
  77. package/src/data-structures/binary-tree/tree-counter.ts +199 -218
  78. package/src/data-structures/binary-tree/tree-multi-map.ts +131 -97
  79. package/src/data-structures/graph/abstract-graph.ts +339 -264
  80. package/src/data-structures/graph/directed-graph.ts +146 -236
  81. package/src/data-structures/graph/map-graph.ts +63 -60
  82. package/src/data-structures/graph/undirected-graph.ts +129 -152
  83. package/src/data-structures/hash/hash-map.ts +274 -496
  84. package/src/data-structures/heap/heap.ts +389 -402
  85. package/src/data-structures/heap/max-heap.ts +12 -76
  86. package/src/data-structures/heap/min-heap.ts +13 -76
  87. package/src/data-structures/linked-list/doubly-linked-list.ts +426 -530
  88. package/src/data-structures/linked-list/singly-linked-list.ts +495 -517
  89. package/src/data-structures/linked-list/skip-linked-list.ts +1 -108
  90. package/src/data-structures/priority-queue/max-priority-queue.ts +12 -87
  91. package/src/data-structures/priority-queue/min-priority-queue.ts +11 -88
  92. package/src/data-structures/priority-queue/priority-queue.ts +3 -92
  93. package/src/data-structures/queue/deque.ts +381 -357
  94. package/src/data-structures/queue/queue.ts +310 -264
  95. package/src/data-structures/stack/stack.ts +217 -131
  96. package/src/data-structures/trie/trie.ts +240 -175
  97. package/src/interfaces/binary-tree.ts +240 -6
  98. package/src/interfaces/graph.ts +37 -0
  99. package/src/types/data-structures/base/base.ts +5 -5
  100. package/src/types/data-structures/graph/abstract-graph.ts +5 -0
  101. package/src/types/utils/utils.ts +2 -0
  102. package/src/utils/utils.ts +9 -14
@@ -5,7 +5,9 @@
5
5
  * @copyright Copyright (c) 2022 Pablo Zeng <zrwusa@gmail.com>
6
6
  * @license MIT License
7
7
  */
8
+
8
9
  import type {
10
+ BinaryTreeOptions,
9
11
  BSTNOptKeyOrNode,
10
12
  BSTOptions,
11
13
  BTNRep,
@@ -25,17 +27,21 @@ import { Queue } from '../queue';
25
27
  import { isComparable } from '../../utils';
26
28
  import { Range } from '../../common';
27
29
 
30
+ /**
31
+ * Represents a Node in a Binary Search Tree.
32
+ *
33
+ * @template K - The type of the key.
34
+ * @template V - The type of the value.
35
+ */
28
36
  export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
29
37
  override parent?: BSTNode<K, V> = undefined;
30
38
 
31
39
  /**
32
- * This TypeScript constructor function initializes an instance with a key and an optional value.
33
- * @param {K} key - The `key` parameter is typically used to uniquely identify an object or element
34
- * within a data structure. It serves as a reference or identifier for accessing or manipulating the
35
- * associated value.
36
- * @param {V} [value] - The `value` parameter in the constructor is optional, meaning it does not
37
- * have to be provided when creating an instance of the class. If a value is not provided, it will
38
- * default to `undefined`.
40
+ * Creates an instance of BSTNode.
41
+ * @remarks Time O(1), Space O(1)
42
+ *
43
+ * @param key - The key of the node.
44
+ * @param [value] - The value associated with the key.
39
45
  */
40
46
  constructor(key: K, value?: V) {
41
47
  super(key, value);
@@ -43,32 +49,58 @@ export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
43
49
 
44
50
  override _left?: BSTNode<K, V> | null | undefined = undefined;
45
51
 
52
+ /**
53
+ * Gets the left child of the node.
54
+ * @remarks Time O(1), Space O(1)
55
+ *
56
+ * @returns The left child.
57
+ */
46
58
  override get left(): BSTNode<K, V> | null | undefined {
47
59
  return this._left;
48
60
  }
49
61
 
62
+ /**
63
+ * Sets the left child of the node and updates its parent reference.
64
+ * @remarks Time O(1), Space O(1)
65
+ *
66
+ * @param v - The node to set as the left child.
67
+ */
50
68
  override set left(v: BSTNode<K, V> | null | undefined) {
51
- if (v) {
52
- v.parent = this;
53
- }
69
+ if (v) v.parent = this;
54
70
  this._left = v;
55
71
  }
56
72
 
57
73
  override _right?: BSTNode<K, V> | null | undefined = undefined;
58
74
 
75
+ /**
76
+ * Gets the right child of the node.
77
+ * @remarks Time O(1), Space O(1)
78
+ *
79
+ * @returns The right child.
80
+ */
59
81
  override get right(): BSTNode<K, V> | null | undefined {
60
82
  return this._right;
61
83
  }
62
84
 
85
+ /**
86
+ * Sets the right child of the node and updates its parent reference.
87
+ * @remarks Time O(1), Space O(1)
88
+ *
89
+ * @param v - The node to set as the right child.
90
+ */
63
91
  override set right(v: BSTNode<K, V> | null | undefined) {
64
- if (v) {
65
- v.parent = this;
66
- }
92
+ if (v) v.parent = this;
67
93
  this._right = v;
68
94
  }
69
95
  }
70
96
 
71
97
  /**
98
+ * Represents a Binary Search Tree (BST).
99
+ * Keys are ordered, allowing for faster search operations compared to a standard Binary Tree.
100
+ * @template K - The type of the key.
101
+ * @template V - The type of the value.
102
+ * @template R - The type of the raw data object (if using `toEntryFn`).
103
+ *
72
104
  * 1. Node Order: Each node's left child has a lesser value, and the right child has a greater value.
73
105
  * 2. Unique Keys: No duplicate keys in a standard BST.
74
106
  * 3. Efficient Search: Enables quick search, minimum, and maximum operations.
@@ -133,18 +165,16 @@ export class BSTNode<K = any, V = any> extends BinaryTreeNode<K, V> {
133
165
  * console.log(findLCA(5, 35)); // 15
134
166
  * console.log(findLCA(20, 30)); // 25
135
167
  */
136
- export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
137
- extends BinaryTree<K, V, R, MK, MV, MR>
138
- implements IBinaryTree<K, V, R, MK, MV, MR>
168
+ export class BST<K = any, V = any, R extends object = object>
169
+ extends BinaryTree<K, V, R>
170
+ implements IBinaryTree<K, V, R>
139
171
  {
140
172
  /**
141
- * This TypeScript constructor initializes a binary search tree with optional options and adds
142
- * elements if provided.
143
- * @param keysNodesEntriesOrRaws - The `keysNodesEntriesOrRaws` parameter in the constructor is an
144
- * iterable that can contain elements of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined ` or `R`. It is used to
145
- * initialize the binary search tree with keys, nodes, entries, or raw data.
146
- * @param [options] - The `options` parameter is an optional object that can contain the following
147
- * properties:
173
+ * Creates an instance of BST.
174
+ * @remarks Time O(N log N) or O(N^2) depending on `isBalanceAdd` in `addMany` and input order. Space O(N).
175
+ *
176
+ * @param [keysNodesEntriesOrRaws=[]] - An iterable of items to add.
177
+ * @param [options] - Configuration options for the BST, including comparator.
148
178
  */
149
179
  constructor(
150
180
  keysNodesEntriesOrRaws: Iterable<
@@ -159,22 +189,37 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
159
189
  if (typeof specifyComparable === 'function') this._specifyComparable = specifyComparable;
160
190
  if (isReverse !== undefined) this._isReverse = isReverse;
161
191
  }
162
-
163
192
  if (keysNodesEntriesOrRaws) this.addMany(keysNodesEntriesOrRaws);
164
193
  }
165
194
 
166
195
  protected override _root?: BSTNode<K, V> = undefined;
167
196
 
197
+ /**
198
+ * Gets the root node of the tree.
199
+ * @remarks Time O(1)
200
+ *
201
+ * @returns The root node.
202
+ */
168
203
  override get root(): OptNode<BSTNode<K, V>> {
169
204
  return this._root;
170
205
  }
171
206
 
172
207
  protected _isReverse: boolean = false;
173
208
 
209
+ /**
210
+ * Gets whether the tree's comparison logic is reversed.
211
+ * @remarks Time O(1)
212
+ *
213
+ * @returns True if the tree is reversed (e.g., a max-heap logic).
214
+ */
174
215
  get isReverse(): boolean {
175
216
  return this._isReverse;
176
217
  }
177
218
 
219
+ /**
220
+ * The default comparator function.
221
+ * @remarks Time O(1) (or O(C) if `specifyComparable` is used, C is complexity of that function).
222
+ */
178
223
  protected _comparator: Comparator<K> = (a: K, b: K): number => {
179
224
  if (isComparable(a) && isComparable(b)) {
180
225
  if (a > b) return 1;
@@ -182,79 +227,61 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
182
227
  return 0;
183
228
  }
184
229
  if (this._specifyComparable) {
185
- if (this._specifyComparable(a) > this._specifyComparable(b)) return 1;
186
- if (this._specifyComparable(a) < this._specifyComparable(b)) return -1;
230
+ const va = this._specifyComparable(a);
231
+ const vb = this._specifyComparable(b);
232
+ if (va > vb) return 1;
233
+ if (va < vb) return -1;
187
234
  return 0;
188
235
  }
189
236
  if (typeof a === 'object' || typeof b === 'object') {
190
237
  throw TypeError(
191
- `When comparing object types, a custom specifyComparable must be defined in the constructor's options parameter.`
238
+ `When comparing object types, a custom specifyComparable must be defined in the constructor's options.`
192
239
  );
193
240
  }
194
-
195
241
  return 0;
196
242
  };
197
243
 
198
- get comparator() {
244
+ /**
245
+ * Gets the comparator function used by the tree.
246
+ * @remarks Time O(1)
247
+ *
248
+ * @returns The comparator function.
249
+ */
250
+ get comparator(): Comparator<K> {
199
251
  return this._comparator;
200
252
  }
201
253
 
202
254
  protected _specifyComparable?: (key: K) => Comparable;
203
255
 
204
- get specifyComparable() {
205
- return this._specifyComparable;
206
- }
207
-
208
256
  /**
209
- * Time Complexity: O(1)
210
- * Space Complexity: O(1)
257
+ * Gets the function used to extract a comparable value from a complex key.
258
+ * @remarks Time O(1)
211
259
  *
212
- * The function creates a new BSTNode with the given key and value and returns it.
213
- * @param {K} key - The key parameter is of type K, which represents the type of the key for the node
214
- * being created.
215
- * @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
216
- * value associated with the key in the node being created.
217
- * @returns The method is returning a new instance of the BSTNode class, casted as the BSTNode<K, V> type.
260
+ * @returns The key-to-comparable conversion function.
218
261
  */
219
- override createNode(key: K, value?: V): BSTNode<K, V> {
220
- return new BSTNode<K, V>(key, this._isMapMode ? undefined : value);
262
+ get specifyComparable(): ((key: K) => Comparable) | undefined {
263
+ return this._specifyComparable;
221
264
  }
222
265
 
223
266
  /**
224
- * Time Complexity: O(1)
225
- * Space Complexity: O(1)
267
+ * (Protected) Creates a new BST node.
268
+ * @remarks Time O(1), Space O(1)
226
269
  *
227
- * The function creates a new binary search tree with the specified options.
228
- * @param [options] - The `options` parameter is an optional object that allows you to customize the
229
- * behavior of the `createTree` method. It accepts a partial `BSTOptions` object, which has the
230
- * following properties:
231
- * @returns a new instance of the BST class with the provided options.
270
+ * @param key - The key for the new node.
271
+ * @param [value] - The value for the new node (used if not in Map mode).
272
+ * @returns The newly created BSTNode.
232
273
  */
233
- override createTree(options?: BSTOptions<K, V, R>) {
234
- return new BST<K, V, R, MK, MV, MR>([], {
235
- iterationType: this.iterationType,
236
- isMapMode: this._isMapMode,
237
- specifyComparable: this._specifyComparable,
238
- toEntryFn: this._toEntryFn,
239
- isReverse: this._isReverse,
240
- ...options
241
- });
274
+ override _createNode(key: K, value?: V): BSTNode<K, V> {
275
+ return new BSTNode<K, V>(key, this._isMapMode ? undefined : value);
242
276
  }
243
277
 
244
278
  /**
245
- * Time Complexity: O(log n)
246
- * Space Complexity: O(log n)
279
+ * Ensures the input is a node. If it's a key or entry, it searches for the node.
280
+ * @remarks Time O(log N) (height of the tree), O(N) worst-case.
247
281
  *
248
- * The function ensures the existence of a node in a data structure and returns it, or undefined if
249
- * it doesn't exist.
250
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
251
- * `keyNodeOrEntry` can accept a value of type `R`, which represents the key, node,
252
- * entry, or raw element that needs to be ensured in the tree.
253
- * @param {IterationType} [iterationType=ITERATIVE] - The `iterationType` parameter is an optional
254
- * parameter that specifies the type of iteration to be used when ensuring a node. It has a default
255
- * value of `'ITERATIVE'`.
256
- * @returns The method is returning either the node that was ensured or `undefined` if the node could
257
- * not be ensured.
282
+ * @param keyNodeOrEntry - The item to resolve to a node.
283
+ * @param [iterationType=this.iterationType] - The traversal method to use if searching.
284
+ * @returns The resolved node, or undefined if not found.
258
285
  */
259
286
  override ensureNode(
260
287
  keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
@@ -264,14 +291,11 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
264
291
  }
265
292
 
266
293
  /**
267
- * Time Complexity: O(1)
268
- * Space Complexity: O(1)
294
+ * Checks if the given item is a `BSTNode` instance.
295
+ * @remarks Time O(1), Space O(1)
269
296
  *
270
- * The function checks if the input is an instance of the BSTNode class.
271
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
272
- * `keyNodeOrEntry` can be of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
273
- * @returns a boolean value indicating whether the input parameter `keyNodeOrEntry` is
274
- * an instance of the `BSTNode` class.
297
+ * @param keyNodeOrEntry - The item to check.
298
+ * @returns True if it's a BSTNode, false otherwise.
275
299
  */
276
300
  override isNode(
277
301
  keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
@@ -280,30 +304,221 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
280
304
  }
281
305
 
282
306
  /**
283
- * Time Complexity: O(1)
284
- * Space Complexity: O(1)
307
+ * Checks if the given key is valid (comparable).
308
+ * @remarks Time O(1)
285
309
  *
286
- * The function "override isValidKey" checks if a key is comparable based on a given comparator.
287
- * @param {any} key - The `key` parameter is a value that will be checked to determine if it is of
288
- * type `K`.
289
- * @returns The `override isValidKey(key: any): key is K` function is returning a boolean value based on
290
- * the result of the `isComparable` function with the condition `this._compare !==
291
- * this._DEFAULT_COMPARATOR`.
310
+ * @param key - The key to validate.
311
+ * @returns True if the key is valid, false otherwise.
292
312
  */
293
313
  override isValidKey(key: any): key is K {
294
314
  return isComparable(key, this._specifyComparable !== undefined);
295
315
  }
296
316
 
297
317
  /**
298
- * Time Complexity: O(log n)
299
- * Space Complexity: O(log n)
318
+ * Performs a Depth-First Search (DFS) traversal.
319
+ * @remarks Time O(N), visits every node. Space O(log N) for the call/explicit stack. O(N) worst-case.
320
+ *
321
+ * @template C - The type of the callback function.
322
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
323
+ * @param [pattern='IN'] - The traversal order ('IN', 'PRE', 'POST').
324
+ * @param [onlyOne=false] - If true, stops after the first callback.
325
+ * @param [startNode=this._root] - The node to start from.
326
+ * @param [iterationType=this.iterationType] - The traversal method.
327
+ * @returns An array of callback results.
328
+ */
329
+ override dfs<C extends NodeCallback<BSTNode<K, V>>>(
330
+ callback: C = this._DEFAULT_NODE_CALLBACK as C,
331
+ pattern: DFSOrderPattern = 'IN',
332
+ onlyOne: boolean = false,
333
+ startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
334
+ iterationType: IterationType = this.iterationType
335
+ ): ReturnType<C>[] {
336
+ return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
337
+ }
338
+
339
+ /**
340
+ * Performs a Breadth-First Search (BFS) or Level-Order traversal.
341
+ * @remarks Time O(N), visits every node. Space O(N) in the worst case for the queue.
300
342
  *
301
- * The `add` function in TypeScript adds a new node to a binary search tree based on the key value.
302
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - The parameter
303
- * `keyNodeOrEntry` can accept a value of type `R` or `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `.
304
- * @param {V} [value] - The `value` parameter is an optional value that can be associated with the
305
- * key in the binary search tree. If provided, it will be stored in the node along with the key.
306
- * @returns a boolean value.
343
+ * @template C - The type of the callback function.
344
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
345
+ * @param [startNode=this._root] - The node to start from.
346
+ * @param [iterationType=this.iterationType] - The traversal method.
347
+ * @returns An array of callback results.
348
+ */
349
+ override bfs<C extends NodeCallback<BSTNode<K, V>>>(
350
+ callback: C = this._DEFAULT_NODE_CALLBACK as C,
351
+ startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
352
+ iterationType: IterationType = this.iterationType
353
+ ): ReturnType<C>[] {
354
+ return super.bfs(callback, startNode, iterationType, false);
355
+ }
356
+
357
+ /**
358
+ * Returns a 2D array of nodes, grouped by level.
359
+ * @remarks Time O(N), visits every node. Space O(N) for the result array and the queue/stack.
360
+ *
361
+ * @template C - The type of the callback function.
362
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each node.
363
+ * @param [startNode=this._root] - The node to start from.
364
+ * @param [iterationType=this.iterationType] - The traversal method.
365
+ * @returns A 2D array of callback results.
366
+ */
367
+ override listLevels<C extends NodeCallback<BSTNode<K, V>>>(
368
+ callback: C = this._DEFAULT_NODE_CALLBACK as C,
369
+ startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
370
+ iterationType: IterationType = this.iterationType
371
+ ): ReturnType<C>[][] {
372
+ return super.listLevels(callback, startNode, iterationType, false);
373
+ }
374
+
375
+ /**
376
+ * Gets the first node matching a predicate.
377
+ * @remarks Time O(log N) if searching by key, O(N) if searching by predicate. Space O(log N) or O(N).
378
+ *
379
+ * @param keyNodeEntryOrPredicate - The key, node, entry, or predicate function to search for.
380
+ * @param [startNode=this._root] - The node to start the search from.
381
+ * @param [iterationType=this.iterationType] - The traversal method.
382
+ * @returns The first matching node, or undefined if not found.
383
+ */
384
+ override getNode(
385
+ keyNodeEntryOrPredicate:
386
+ | K
387
+ | BSTNode<K, V>
388
+ | [K | null | undefined, V | undefined]
389
+ | null
390
+ | undefined
391
+ | NodePredicate<BSTNode<K, V>>,
392
+ startNode: BSTNOptKeyOrNode<K, BSTNode<K, V>> = this._root,
393
+ iterationType: IterationType = this.iterationType
394
+ ): OptNode<BSTNode<K, V>> {
395
+ return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? undefined;
396
+ }
397
+
398
+ /**
399
+ * Searches the tree for nodes matching a predicate, key, or range.
400
+ * @remarks This is an optimized search for a BST. If searching by key or range, it prunes branches.
401
+ * Time O(H + M) for key/range search (H=height, M=matches). O(N) for predicate search.
402
+ * Space O(log N) for the stack.
403
+ *
404
+ * @template C - The type of the callback function.
405
+ * @param keyNodeEntryOrPredicate - The key, node, entry, predicate, or range to search for.
406
+ * @param [onlyOne=false] - If true, stops after finding the first match.
407
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
408
+ * @param [startNode=this._root] - The node to start the search from.
409
+ * @param [iterationType=this.iterationType] - Whether to use 'RECURSIVE' or 'ITERATIVE' search.
410
+ * @returns An array of results from the callback function for each matching node.
411
+ */
412
+ override search<C extends NodeCallback<BSTNode<K, V>>>(
413
+ keyNodeEntryOrPredicate:
414
+ | K
415
+ | BSTNode<K, V>
416
+ | [K | null | undefined, V | undefined]
417
+ | null
418
+ | undefined
419
+ | NodePredicate<BSTNode<K, V>>
420
+ | Range<K>,
421
+ onlyOne = false,
422
+ callback: C = this._DEFAULT_NODE_CALLBACK as C,
423
+ startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
424
+ iterationType: IterationType = this.iterationType
425
+ ): ReturnType<C>[] {
426
+ if (keyNodeEntryOrPredicate === undefined) return [];
427
+ if (keyNodeEntryOrPredicate === null) return [];
428
+ startNode = this.ensureNode(startNode);
429
+ if (!startNode) return [];
430
+
431
+ let predicate: NodePredicate<BSTNode<K, V>>;
432
+ const isRange = this.isRange(keyNodeEntryOrPredicate);
433
+
434
+ if (isRange) {
435
+ predicate = node => {
436
+ if (!node) return false;
437
+ return (keyNodeEntryOrPredicate as Range<K>).isInRange(node.key, this._comparator);
438
+ };
439
+ } else {
440
+ predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
441
+ }
442
+
443
+ // Optimization: Pruning logic
444
+ const shouldVisitLeft = (cur: BSTNode<K, V> | null | undefined) => {
445
+ if (!cur) return false;
446
+ if (!this.isRealNode(cur.left)) return false;
447
+ if (isRange) {
448
+ // Range search: Only go left if the current key is >= the lower bound
449
+ const range = keyNodeEntryOrPredicate as Range<K>;
450
+ const leftS = this.isReverse ? range.high : range.low;
451
+ const leftI = this.isReverse ? range.includeHigh : range.includeLow;
452
+ return (leftI && this._compare(cur.key, leftS) >= 0) || (!leftI && this._compare(cur.key, leftS) > 0);
453
+ }
454
+ if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
455
+ // Key search: Only go left if current key > target key
456
+ const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
457
+ return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) > 0;
458
+ }
459
+ return true; // Predicate search: must visit all
460
+ };
461
+
462
+ const shouldVisitRight = (cur: BSTNode<K, V> | null | undefined) => {
463
+ if (!cur) return false;
464
+ if (!this.isRealNode(cur.right)) return false;
465
+ if (isRange) {
466
+ // Range search: Only go right if current key <= upper bound
467
+ const range = keyNodeEntryOrPredicate as Range<K>;
468
+ const rightS = this.isReverse ? range.low : range.high;
469
+ const rightI = this.isReverse ? range.includeLow : range.includeHigh;
470
+ return (rightI && this._compare(cur.key, rightS) <= 0) || (!rightI && this._compare(cur.key, rightS) < 0);
471
+ }
472
+ if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
473
+ // Key search: Only go right if current key < target key
474
+ const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
475
+ return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) < 0;
476
+ }
477
+ return true; // Predicate search: must visit all
478
+ };
479
+
480
+ return super._dfs(
481
+ callback,
482
+ 'IN', // In-order is efficient for range/key search
483
+ onlyOne,
484
+ startNode,
485
+ iterationType,
486
+ false,
487
+ shouldVisitLeft,
488
+ shouldVisitRight,
489
+ () => true, // shouldVisitRoot (always visit)
490
+ cur => !!cur && predicate(cur) // shouldProcessRoot (only process if predicate matches)
491
+ );
492
+ }
493
+
494
+ /**
495
+ * Performs an optimized search for nodes within a given key range.
496
+ * @remarks Time O(H + M), where H is tree height and M is the number of matches.
497
+ *
498
+ * @template C - The type of the callback function.
499
+ * @param range - A `Range` object or a `[low, high]` tuple.
500
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - A function to call on matching nodes.
501
+ * @param [startNode=this._root] - The node to start the search from.
502
+ * @param [iterationType=this.iterationType] - The traversal method.
503
+ * @returns An array of callback results.
504
+ */
505
+ rangeSearch<C extends NodeCallback<BSTNode<K, V>>>(
506
+ range: Range<K> | [K, K],
507
+ callback: C = this._DEFAULT_NODE_CALLBACK as C,
508
+ startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
509
+ iterationType: IterationType = this.iterationType
510
+ ) {
511
+ const searchRange: Range<K> = range instanceof Range ? range : new Range(range[0], range[1]);
512
+ return this.search(searchRange, false, callback, startNode, iterationType);
513
+ }
514
+
515
+ /**
516
+ * Adds a new node to the BST based on key comparison.
517
+ * @remarks Time O(log N), where H is tree height. O(N) worst-case (unbalanced tree), O(log N) average. Space O(1).
518
+ *
519
+ * @param keyNodeOrEntry - The key, node, or entry to add.
520
+ * @param [value] - The value, if providing just a key.
521
+ * @returns True if the addition was successful, false otherwise.
307
522
  */
308
523
  override add(
309
524
  keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
@@ -322,10 +537,12 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
322
537
  let current = this._root;
323
538
  while (current !== undefined) {
324
539
  if (this._compare(current.key, newNode.key) === 0) {
540
+ // Key exists, replace node
325
541
  this._replaceNode(current, newNode);
326
542
  if (this._isMapMode) this._setValue(current.key, newValue);
327
543
  return true;
328
544
  } else if (this._compare(current.key, newNode.key) > 0) {
545
+ // Go left
329
546
  if (current.left === undefined) {
330
547
  current.left = newNode;
331
548
  if (this._isMapMode) this._setValue(newNode?.key, newValue);
@@ -334,6 +551,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
334
551
  }
335
552
  if (current.left !== null) current = current.left;
336
553
  } else {
554
+ // Go right
337
555
  if (current.right === undefined) {
338
556
  current.right = newNode;
339
557
  if (this._isMapMode) this._setValue(newNode?.key, newValue);
@@ -343,30 +561,20 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
343
561
  if (current.right !== null) current = current.right;
344
562
  }
345
563
  }
346
-
347
564
  return false;
348
565
  }
349
566
 
350
567
  /**
351
- * Time Complexity: O(k log n)
352
- * Space Complexity: O(k + log n)
568
+ * Adds multiple items to the tree.
569
+ * @remarks If `isBalanceAdd` is true, sorts the input and builds a balanced tree. Time O(N log N) (due to sort and balanced add).
570
+ * If false, adds items one by one. Time O(N * H), which is O(N^2) worst-case.
571
+ * Space O(N) for sorting and recursion/iteration stack.
353
572
  *
354
- * The `addMany` function in TypeScript adds multiple keys or nodes to a data structure and returns
355
- * an array indicating whether each key or node was successfully inserted.
356
- * @param keysNodesEntriesOrRaws - An iterable containing keys, nodes, entries, or raw
357
- * elements to be added to the data structure.
358
- * @param [values] - An optional iterable of values to be associated with the keys or nodes being
359
- * added. If provided, the values will be assigned to the corresponding keys or nodes in the same
360
- * order. If not provided, undefined will be assigned as the value for each key or node.
361
- * @param [isBalanceAdd=true] - A boolean flag indicating whether the tree should be balanced after
362
- * adding the elements. If set to true, the tree will be balanced using a binary search tree
363
- * algorithm. If set to false, the elements will be added without balancing the tree. The default
364
- * value is true.
365
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
366
- * specifies the type of iteration to use when adding multiple keys or nodes to the binary search
367
- * tree. It can have two possible values:
368
- * @returns The function `addMany` returns an array of booleans indicating whether each element was
369
- * successfully inserted into the data structure.
573
+ * @param keysNodesEntriesOrRaws - An iterable of items to add.
574
+ * @param [values] - An optional parallel iterable of values.
575
+ * @param [isBalanceAdd=true] - If true, builds a balanced tree from the items.
576
+ * @param [iterationType=this.iterationType] - The traversal method for balanced add (recursive or iterative).
577
+ * @returns An array of booleans indicating the success of each individual `add` operation.
370
578
  */
371
579
  override addMany(
372
580
  keysNodesEntriesOrRaws: Iterable<R | BTNRep<K, V, BSTNode<K, V>>>,
@@ -375,22 +583,19 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
375
583
  iterationType: IterationType = this.iterationType
376
584
  ): boolean[] {
377
585
  const inserted: boolean[] = [];
378
-
379
- let valuesIterator: Iterator<V | undefined> | undefined;
380
-
381
- if (values) {
382
- valuesIterator = values[Symbol.iterator]();
383
- }
586
+ const valuesIterator: Iterator<V | undefined> | undefined = values?.[Symbol.iterator]();
384
587
 
385
588
  if (!isBalanceAdd) {
589
+ // Standard O(N*H) insertion
386
590
  for (let kve of keysNodesEntriesOrRaws) {
387
- const value = valuesIterator?.next().value;
591
+ const val = valuesIterator?.next().value;
388
592
  if (this.isRaw(kve)) kve = this._toEntryFn!(kve);
389
- inserted.push(this.add(kve, value));
593
+ inserted.push(this.add(kve, val));
390
594
  }
391
595
  return inserted;
392
596
  }
393
597
 
598
+ // Balanced O(N log N) insertion
394
599
  const realBTNExemplars: {
395
600
  key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
396
601
  value: V | undefined;
@@ -399,50 +604,31 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
399
604
 
400
605
  let i = 0;
401
606
  for (const kve of keysNodesEntriesOrRaws) {
402
- realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i });
403
- i++;
607
+ realBTNExemplars.push({ key: kve, value: valuesIterator?.next().value, orgIndex: i++ });
404
608
  }
405
609
 
406
- let sorted: {
407
- key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
408
- value: V | undefined;
409
- orgIndex: number;
410
- }[] = [];
411
-
412
- sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
610
+ // Sort items by key
611
+ const sorted = realBTNExemplars.sort(({ key: a }, { key: b }) => {
413
612
  let keyA: K | undefined | null, keyB: K | undefined | null;
414
613
  if (this.isRaw(a)) keyA = this._toEntryFn!(a)[0];
415
614
  else if (this.isEntry(a)) keyA = a[0];
416
615
  else if (this.isRealNode(a)) keyA = a.key;
417
- else {
418
- keyA = a as K;
419
- }
616
+ else keyA = a as K;
420
617
 
421
618
  if (this.isRaw(b)) keyB = this._toEntryFn!(b)[0];
422
619
  else if (this.isEntry(b)) keyB = b[0];
423
620
  else if (this.isRealNode(b)) keyB = b.key;
424
- else {
425
- keyB = b as K;
426
- }
621
+ else keyB = b as K;
427
622
 
428
- if (keyA !== undefined && keyA !== null && keyB !== undefined && keyB !== null) {
429
- return this._compare(keyA, keyB);
430
- }
623
+ if (keyA != null && keyB != null) return this._compare(keyA, keyB);
431
624
  return 0;
432
625
  });
433
626
 
434
- const _dfs = (
435
- arr: {
436
- key: R | K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined;
437
- value: V | undefined;
438
- orgIndex: number;
439
- }[]
440
- ) => {
627
+ // Recursive balanced build
628
+ const _dfs = (arr: typeof realBTNExemplars) => {
441
629
  if (arr.length === 0) return;
442
-
443
630
  const mid = Math.floor((arr.length - 1) / 2);
444
- const { key, value } = arr[mid];
445
- const { orgIndex } = arr[mid];
631
+ const { key, value, orgIndex } = arr[mid];
446
632
  if (this.isRaw(key)) {
447
633
  const entry = this._toEntryFn!(key);
448
634
  inserted[orgIndex] = this.add(entry);
@@ -453,318 +639,44 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
453
639
  _dfs(arr.slice(mid + 1));
454
640
  };
455
641
 
642
+ // Iterative balanced build
456
643
  const _iterate = () => {
457
644
  const n = sorted.length;
458
- const stack: [[number, number]] = [[0, n - 1]];
645
+ const stack: Array<[number, number]> = [[0, n - 1]];
459
646
  while (stack.length > 0) {
460
647
  const popped = stack.pop();
461
- if (popped) {
462
- const [l, r] = popped;
463
- if (l <= r) {
464
- const m = l + Math.floor((r - l) / 2);
465
- const { key, value } = sorted[m];
466
- const { orgIndex } = sorted[m];
467
- if (this.isRaw(key)) {
468
- const entry = this._toEntryFn!(key);
469
- inserted[orgIndex] = this.add(entry);
470
- } else {
471
- inserted[orgIndex] = this.add(key, value);
472
- }
473
- stack.push([m + 1, r]);
474
- stack.push([l, m - 1]);
475
- }
648
+ if (!popped) continue;
649
+ const [l, r] = popped;
650
+ if (l > r) continue;
651
+ const m = l + Math.floor((r - l) / 2);
652
+ const { key, value, orgIndex } = sorted[m];
653
+ if (this.isRaw(key)) {
654
+ const entry = this._toEntryFn!(key);
655
+ inserted[orgIndex] = this.add(entry);
656
+ } else {
657
+ inserted[orgIndex] = this.add(key, value);
476
658
  }
659
+ stack.push([m + 1, r]);
660
+ stack.push([l, m - 1]);
477
661
  }
478
662
  };
479
663
 
480
- if (iterationType === 'RECURSIVE') {
481
- _dfs(sorted);
482
- } else {
483
- _iterate();
484
- }
664
+ if (iterationType === 'RECURSIVE') _dfs(sorted);
665
+ else _iterate();
485
666
 
486
667
  return inserted;
487
668
  }
488
669
 
489
670
  /**
490
- * Time Complexity: O(log n)
491
- * Space Complexity: O(k + log n)
492
- *
493
- * The function `search` in TypeScript overrides the search behavior in a binary tree structure based
494
- * on specified criteria.
495
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The
496
- * `keyNodeEntryOrPredicate` parameter in the `override search` method can accept one of the
497
- * following types:
498
- * @param [onlyOne=false] - The `onlyOne` parameter is a boolean flag that determines whether the
499
- * search should stop after finding the first matching node. If `onlyOne` is set to `true`, the
500
- * search will return as soon as a matching node is found. If `onlyOne` is set to `false`, the
501
- * @param {C} callback - The `callback` parameter in the `override search` function is a function
502
- * that will be called on each node that matches the search criteria. It is of type `C`, which
503
- * extends `NodeCallback<BSTNode<K, V> | null>`. The callback function should accept a node of type `BSTNode<K, V>` as its
504
- * argument and
505
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `override search`
506
- * method represents the node from which the search operation will begin. It is the starting point
507
- * for searching within the tree data structure. The method ensures that the `startNode` is a valid
508
- * node before proceeding with the search operation. If the `
509
- * @param {IterationType} iterationType - The `iterationType` parameter in the `override search`
510
- * function determines the type of iteration to be used during the search operation. It can have two
511
- * possible values:
512
- * @returns The `override search` method returns an array of values that match the search criteria
513
- * specified by the input parameters. The method performs a search operation on a binary tree
514
- * structure based on the provided key, predicate, and other options. The search results are
515
- * collected in an array and returned as the output of the method.
516
- */
517
- override search<C extends NodeCallback<BSTNode<K, V>>>(
518
- keyNodeEntryOrPredicate:
519
- | K
520
- | BSTNode<K, V>
521
- | [K | null | undefined, V | undefined]
522
- | null
523
- | undefined
524
- | NodePredicate<BSTNode<K, V>>
525
- | Range<K>,
526
- onlyOne = false,
527
- callback: C = this._DEFAULT_NODE_CALLBACK as C,
528
- startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
529
- iterationType: IterationType = this.iterationType
530
- ): ReturnType<C>[] {
531
- if (keyNodeEntryOrPredicate === undefined) return [];
532
- if (keyNodeEntryOrPredicate === null) return [];
533
- startNode = this.ensureNode(startNode);
534
- if (!startNode) return [];
535
- let predicate: NodePredicate<BSTNode<K, V>>;
536
-
537
- const isRange = this.isRange(keyNodeEntryOrPredicate);
538
- // Set predicate based on parameter type
539
- if (isRange) {
540
- predicate = node => {
541
- if (!node) return false;
542
- return keyNodeEntryOrPredicate.isInRange(node.key, this._comparator);
543
- };
544
- } else {
545
- predicate = this._ensurePredicate(keyNodeEntryOrPredicate);
546
- }
547
- const shouldVisitLeft = (cur: BSTNode<K, V> | null | undefined) => {
548
- if (!cur) return false;
549
- if (!this.isRealNode(cur.left)) return false;
550
- if (isRange) {
551
- const range = keyNodeEntryOrPredicate;
552
- const leftS = this.isReverse ? range.high : range.low;
553
- const leftI = this.isReverse ? range.includeHigh : range.includeLow;
554
- return (leftI && this._compare(cur.key, leftS) >= 0) || (!leftI && this._compare(cur.key, leftS) > 0);
555
- }
556
- if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
557
- const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
558
- return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) > 0;
559
- }
560
- return true;
561
- };
562
-
563
- const shouldVisitRight = (cur: BSTNode<K, V> | null | undefined) => {
564
- if (!cur) return false;
565
- if (!this.isRealNode(cur.right)) return false;
566
- if (isRange) {
567
- const range = keyNodeEntryOrPredicate;
568
- const rightS = this.isReverse ? range.low : range.high;
569
- const rightI = this.isReverse ? range.includeLow : range.includeLow;
570
-
571
- return (rightI && this._compare(cur.key, rightS) <= 0) || (!rightI && this._compare(cur.key, rightS) < 0);
572
- }
573
- if (!isRange && !this._isPredicate(keyNodeEntryOrPredicate)) {
574
- const benchmarkKey = this._extractKey(keyNodeEntryOrPredicate);
575
- return benchmarkKey !== null && benchmarkKey !== undefined && this._compare(cur.key, benchmarkKey) < 0;
576
- }
577
- return true;
578
- };
579
- return super._dfs(
580
- callback,
581
- 'IN',
582
- onlyOne,
583
- startNode,
584
- iterationType,
585
- false,
586
- shouldVisitLeft,
587
- shouldVisitRight,
588
- () => true,
589
- cur => {
590
- if (cur) return predicate(cur);
591
- return false;
592
- }
593
- );
594
- }
595
-
596
- /**
597
- * Time Complexity: O(log n)
598
- * Space Complexity: O(k + log n)
599
- *
600
- * The `rangeSearch` function searches for nodes within a specified range in a binary search tree.
601
- * @param {Range<K> | [K, K]} range - The `range` parameter in the `rangeSearch` function can be
602
- * either a `Range` object or an array of two elements representing the range boundaries.
603
- * @param {C} callback - The `callback` parameter in the `rangeSearch` function is a callback
604
- * function that is used to process each node that is found within the specified range during the
605
- * search operation. It is of type `NodeCallback<BSTNode<K, V> | null>`, where `BSTNode<K, V>` is the type of nodes in the
606
- * data structure.
607
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter in the `rangeSearch`
608
- * function represents the node from which the search for nodes within the specified range will
609
- * begin. It is the starting point for the range search operation.
610
- * @param {IterationType} iterationType - The `iterationType` parameter in the `rangeSearch` function
611
- * is used to specify the type of iteration to be performed during the search operation. It has a
612
- * default value of `this.iterationType`, which suggests that it is likely a property of the class or
613
- * object that the `rangeSearch`
614
- * @returns The `rangeSearch` function is returning the result of calling the `search` method with
615
- * the specified parameters.
616
- */
617
- rangeSearch<C extends NodeCallback<BSTNode<K, V>>>(
618
- range: Range<K> | [K, K],
619
- callback: C = this._DEFAULT_NODE_CALLBACK as C,
620
- startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
621
- iterationType: IterationType = this.iterationType
622
- ) {
623
- const searchRange: Range<K> = range instanceof Range ? range : new Range(range[0], range[1]);
624
- return this.search(searchRange, false, callback, startNode, iterationType);
625
- }
626
-
627
- /**
628
- * Time Complexity: O(log n)
629
- * Space Complexity: O(log n)
630
- *
631
- * This function retrieves a node based on a given keyNodeEntryOrPredicate within a binary search tree structure.
632
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined | NodePredicate<BSTNode<K, V>>} keyNodeEntryOrPredicate - The `keyNodeEntryOrPredicate`
633
- * parameter can be of type `K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined `, `R`, or `NodePredicate<BSTNode<K, V>>`.
634
- * @param {BSTNOptKeyOrNode<K, BSTNode<K, V>>} startNode - The `startNode` parameter in the `getNode` method
635
- * is used to specify the starting point for searching nodes in the binary search tree. If no
636
- * specific starting point is provided, the default value is set to `this._root`, which is the root
637
- * node of the binary search tree.
638
- * @param {IterationType} iterationType - The `iterationType` parameter in the `getNode` method is a
639
- * parameter that specifies the type of iteration to be used. It has a default value of
640
- * `this.iterationType`, which means it will use the iteration type defined in the class instance if
641
- * no value is provided when calling the method.
642
- * @returns The `getNode` method is returning an optional binary search tree node (`OptNode<BSTNode<K, V>>`).
643
- * It is using the `getNodes` method to find the node based on the provided keyNodeEntryOrPredicate, beginning at
644
- * the specified root node (`startNode`) and using the specified iteration type. The method then
645
- * returns the first node found or `undefined` if no node is found.
646
- */
647
- override getNode(
648
- keyNodeEntryOrPredicate:
649
- | K
650
- | BSTNode<K, V>
651
- | [K | null | undefined, V | undefined]
652
- | null
653
- | undefined
654
- | NodePredicate<BSTNode<K, V>>,
655
- startNode: BSTNOptKeyOrNode<K, BSTNode<K, V>> = this._root,
656
- iterationType: IterationType = this.iterationType
657
- ): OptNode<BSTNode<K, V>> {
658
- return this.getNodes(keyNodeEntryOrPredicate, true, startNode, iterationType)[0] ?? undefined;
659
- }
660
-
661
- /**
662
- * Time complexity: O(n)
663
- * Space complexity: O(n)
664
- *
665
- * The function `dfs` in TypeScript overrides the base class method with default parameters and
666
- * returns the result of the super class `dfs` method.
667
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
668
- * visited during the Depth-First Search traversal. It is a generic type `C` that extends the
669
- * `NodeCallback` interface for `BSTNode<K, V>`. The default value for `callback` is `this._
670
- * @param {DFSOrderPattern} [pattern=IN] - The `pattern` parameter in the `override dfs` method
671
- * specifies the order in which the Depth-First Search (DFS) traversal should be performed on the
672
- * Binary Search Tree (BST). The possible values for the `pattern` parameter are:
673
- * @param {boolean} [onlyOne=false] - The `onlyOne` parameter in the `override dfs` method is a
674
- * boolean flag that indicates whether you want to stop the depth-first search traversal after
675
- * finding the first matching node or continue searching for all matching nodes. If `onlyOne` is set
676
- * to `true`, the traversal will stop after finding
677
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined} startNode -
678
- * The `startNode` parameter in the `override dfs` method can be one of the following types:
679
- * @param {IterationType} iterationType - The `iterationType` parameter in the `override dfs` method
680
- * specifies the type of iteration to be performed during the Depth-First Search (DFS) traversal of a
681
- * Binary Search Tree (BST). It is used to determine the order in which nodes are visited during the
682
- * traversal. The possible values for `
683
- * @returns The `override` function is returning the result of calling the `dfs` method from the
684
- * superclass, with the provided arguments `callback`, `pattern`, `onlyOne`, `startNode`, and
685
- * `iterationType`. The return type is an array of the return type of the callback function `C`.
686
- */
687
- override dfs<C extends NodeCallback<BSTNode<K, V>>>(
688
- callback: C = this._DEFAULT_NODE_CALLBACK as C,
689
- pattern: DFSOrderPattern = 'IN',
690
- onlyOne: boolean = false,
691
- startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
692
- iterationType: IterationType = this.iterationType
693
- ): ReturnType<C>[] {
694
- return super.dfs(callback, pattern, onlyOne, startNode, iterationType);
695
- }
696
-
697
- /**
698
- * Time complexity: O(n)
699
- * Space complexity: O(n)
671
+ * Traverses the tree and returns nodes that are lesser or greater than a target node.
672
+ * @remarks Time O(N), as it performs a full traversal. Space O(log N) or O(N).
700
673
  *
701
- * The function overrides the breadth-first search method and returns an array of the return types of
702
- * the callback function.
703
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
704
- * visited during the breadth-first search. It should take a single argument, which is the current
705
- * node being visited, and it can return a value of any type.
706
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
707
- * point for the breadth-first search. It can be either a root node, a key-value pair, or an entry
708
- * object. If no value is provided, the default value is the root of the tree.
709
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
710
- * of iteration to be performed during the breadth-first search (BFS) traversal. It can have one of
711
- * the following values:
712
- * @returns an array of the return type of the callback function.
713
- */
714
- override bfs<C extends NodeCallback<BSTNode<K, V>>>(
715
- callback: C = this._DEFAULT_NODE_CALLBACK as C,
716
- startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
717
- iterationType: IterationType = this.iterationType
718
- ): ReturnType<C>[] {
719
- return super.bfs(callback, startNode, iterationType, false);
720
- }
721
-
722
- /**
723
- * Time complexity: O(n)
724
- * Space complexity: O(n)
725
- *
726
- * The function overrides the listLevels method from the superclass and returns an array of arrays
727
- * containing the results of the callback function applied to each level of the tree.
728
- * @param {C} callback - The `callback` parameter is a generic type `C` that extends
729
- * `NodeCallback<BSTNode<K, V> | null>`. It represents a callback function that will be called for each node in the
730
- * tree during the iteration process.
731
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } startNode - The `startNode` parameter is the starting
732
- * point for listing the levels of the binary tree. It can be either a root node of the tree, a
733
- * key-value pair representing a node in the tree, or a key representing a node in the tree. If no
734
- * value is provided, the root of
735
- * @param {IterationType} iterationType - The `iterationType` parameter is used to specify the type
736
- * of iteration to be performed on the tree. It can have one of the following values:
737
- * @returns The method is returning a two-dimensional array of the return type of the callback
738
- * function.
739
- */
740
- override listLevels<C extends NodeCallback<BSTNode<K, V>>>(
741
- callback: C = this._DEFAULT_NODE_CALLBACK as C,
742
- startNode: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
743
- iterationType: IterationType = this.iterationType
744
- ): ReturnType<C>[][] {
745
- return super.listLevels(callback, startNode, iterationType, false);
746
- }
747
-
748
- /**
749
- * Time complexity: O(n)
750
- * Space complexity: O(n)
751
- *
752
- * The `lesserOrGreaterTraverse` function traverses a binary tree and applies a callback function to
753
- * each node that meets a certain condition based on a target node and a comparison value.
754
- * @param {C} callback - The `callback` parameter is a function that will be called for each node
755
- * that meets the condition specified by the `lesserOrGreater` parameter. It takes a single argument,
756
- * which is the current node being traversed, and returns a value of any type.
757
- * @param {CP} lesserOrGreater - The `lesserOrGreater` parameter is used to determine whether to
758
- * traverse nodes that are lesser, greater, or both than the `targetNode`. It accepts the values -1,
759
- * 0, or 1, where:
760
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } targetNode - The `targetNode` parameter is the node in
761
- * the binary tree that you want to start traversing from. It can be specified either by providing
762
- * the key of the node, the node itself, or an entry containing the key and value of the node. If no
763
- * `targetNode` is provided,
764
- * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
765
- * traversal to be performed on the binary tree. It can have two possible values:
766
- * @returns The function `lesserOrGreaterTraverse` returns an array of values of type
767
- * `ReturnType<C>`, which is the return type of the callback function passed as an argument.
674
+ * @template C - The type of the callback function.
675
+ * @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on matching nodes.
676
+ * @param [lesserOrGreater=-1] - -1 for lesser, 1 for greater, 0 for equal.
677
+ * @param [targetNode=this._root] - The node to compare against.
678
+ * @param [iterationType=this.iterationType] - The traversal method.
679
+ * @returns An array of callback results.
768
680
  */
769
681
  lesserOrGreaterTraverse<C extends NodeCallback<BSTNode<K, V>>>(
770
682
  callback: C = this._DEFAULT_NODE_CALLBACK as C,
@@ -774,20 +686,18 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
774
686
  ): ReturnType<C>[] {
775
687
  const targetNodeEnsured = this.ensureNode(targetNode);
776
688
  const ans: ReturnType<NodeCallback<BSTNode<K, V>>>[] = [];
777
- if (!this._root) return ans;
778
- if (!targetNodeEnsured) return ans;
689
+ if (!this._root || !targetNodeEnsured) return ans;
779
690
 
780
691
  const targetKey = targetNodeEnsured.key;
781
692
 
782
693
  if (iterationType === 'RECURSIVE') {
783
694
  const dfs = (cur: BSTNode<K, V>) => {
784
695
  const compared = this._compare(cur.key, targetKey);
785
- if (Math.sign(compared) === lesserOrGreater) ans.push(callback(cur));
786
- // TODO here can be optimized to O(log n)
696
+ if (Math.sign(compared) == lesserOrGreater) ans.push(callback(cur));
697
+
787
698
  if (this.isRealNode(cur.left)) dfs(cur.left);
788
699
  if (this.isRealNode(cur.right)) dfs(cur.right);
789
700
  };
790
-
791
701
  dfs(this._root);
792
702
  return ans;
793
703
  } else {
@@ -796,8 +706,7 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
796
706
  const cur = queue.shift();
797
707
  if (this.isRealNode(cur)) {
798
708
  const compared = this._compare(cur.key, targetKey);
799
- if (Math.sign(compared) === lesserOrGreater) ans.push(callback(cur));
800
-
709
+ if (Math.sign(compared) == lesserOrGreater) ans.push(callback(cur));
801
710
  if (this.isRealNode(cur.left)) queue.push(cur.left);
802
711
  if (this.isRealNode(cur.right)) queue.push(cur.right);
803
712
  }
@@ -807,83 +716,60 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
807
716
  }
808
717
 
809
718
  /**
810
- * Time complexity: O(n)
811
- * Space complexity: O(n)
719
+ * Rebuilds the tree to be perfectly balanced.
720
+ * @remarks Time O(N) (O(N) for DFS, O(N) for sorted build). Space O(N) for node array and recursion stack.
812
721
  *
813
- * The `perfectlyBalance` function takes an optional `iterationType` parameter and returns `true` if
814
- * the binary search tree is perfectly balanced, otherwise it returns `false`.
815
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
816
- * specifies the type of iteration to use when building a balanced binary search tree. It has a
817
- * default value of `this.iterationType`, which means it will use the iteration type specified in the
818
- * current instance of the class.
819
- * @returns The function `perfectlyBalance` returns a boolean value.
722
+ * @param [iterationType=this.iterationType] - The traversal method for the initial node export.
723
+ * @returns True if successful, false if the tree was empty.
820
724
  */
821
725
  perfectlyBalance(iterationType: IterationType = this.iterationType): boolean {
822
- const sorted = this.dfs(node => node, 'IN'),
823
- n = sorted.length;
726
+ const nodes = this.dfs(node => node, 'IN', false, this._root, iterationType);
727
+ const n = nodes.length;
824
728
  this._clearNodes();
729
+ if (n === 0) return false;
730
+
731
+ // Build balanced tree from sorted array
732
+ const build = (l: number, r: number, parent?: BSTNode<K, V>): BSTNode<K, V> | undefined => {
733
+ if (l > r) return undefined;
734
+ const m = l + ((r - l) >> 1);
735
+ const root = nodes[m]! as BSTNode<K, V>;
736
+ const leftChild = build(l, m - 1, root);
737
+ const rightChild = build(m + 1, r, root);
738
+ root.left = leftChild;
739
+ root.right = rightChild;
740
+ root.parent = parent;
741
+ return root;
742
+ };
825
743
 
826
- if (sorted.length < 1) return false;
827
- if (iterationType === 'RECURSIVE') {
828
- const buildBalanceBST = (l: number, r: number) => {
829
- if (l > r) return;
830
- const m = l + Math.floor((r - l) / 2);
831
- const midNode = sorted[m];
832
- if (this._isMapMode && midNode !== null) this.add(midNode.key);
833
- else if (midNode !== null) this.add([midNode.key, midNode.value]);
834
- buildBalanceBST(l, m - 1);
835
- buildBalanceBST(m + 1, r);
836
- };
837
-
838
- buildBalanceBST(0, n - 1);
839
- return true;
840
- } else {
841
- const stack: [[number, number]] = [[0, n - 1]];
842
- while (stack.length > 0) {
843
- const popped = stack.pop();
844
- if (popped) {
845
- const [l, r] = popped;
846
- if (l <= r) {
847
- const m = l + Math.floor((r - l) / 2);
848
- const midNode = sorted[m];
849
- if (this._isMapMode && midNode !== null) this.add(midNode.key);
850
- else if (midNode !== null) this.add([midNode.key, midNode.value]);
851
- stack.push([m + 1, r]);
852
- stack.push([l, m - 1]);
853
- }
854
- }
855
- }
856
- return true;
857
- }
744
+ const newRoot = build(0, n - 1, undefined);
745
+ this._setRoot(newRoot);
746
+ this._size = n;
747
+ return true;
858
748
  }
859
749
 
860
750
  /**
861
- * Time Complexity: O(n)
862
- * Space Complexity: O(log n)
751
+ * Checks if the tree meets the AVL balance condition (height difference <= 1).
752
+ * @remarks Time O(N), as it must visit every node to compute height. Space O(log N) for recursion or O(N) for iterative map.
863
753
  *
864
- * The function `isAVLBalanced` checks if a binary tree is AVL balanced using either a recursive or
865
- * iterative approach.
866
- * @param {IterationType} iterationType - The `iterationType` parameter is an optional parameter that
867
- * specifies the type of iteration to use when checking if the AVL tree is balanced. It has a default
868
- * value of `this.iterationType`, which means it will use the iteration type specified in the current
869
- * instance of the AVL tree.
870
- * @returns a boolean value.
754
+ * @param [iterationType=this.iterationType] - The traversal method.
755
+ * @returns True if the tree is AVL balanced, false otherwise.
871
756
  */
872
757
  isAVLBalanced(iterationType: IterationType = this.iterationType): boolean {
873
758
  if (!this._root) return true;
874
-
875
759
  let balanced = true;
876
760
 
877
761
  if (iterationType === 'RECURSIVE') {
762
+ // Recursive height check
878
763
  const _height = (cur: BSTNode<K, V> | null | undefined): number => {
879
764
  if (!cur) return 0;
880
- const leftHeight = _height(cur.left),
881
- rightHeight = _height(cur.right);
765
+ const leftHeight = _height(cur.left);
766
+ const rightHeight = _height(cur.right);
882
767
  if (Math.abs(leftHeight - rightHeight) > 1) balanced = false;
883
768
  return Math.max(leftHeight, rightHeight) + 1;
884
769
  };
885
770
  _height(this._root);
886
771
  } else {
772
+ // Iterative post-order height check
887
773
  const stack: BSTNode<K, V>[] = [];
888
774
  let node: OptNode<BSTNode<K, V>> = this._root,
889
775
  last: OptNode<BSTNode<K, V>> = undefined;
@@ -909,107 +795,219 @@ export class BST<K = any, V = any, R = object, MK = any, MV = any, MR = object>
909
795
  }
910
796
  }
911
797
  }
912
-
913
798
  return balanced;
914
799
  }
915
800
 
916
801
  /**
917
- * Time complexity: O(n)
918
- * Space complexity: O(n)
802
+ * Creates a new BST by mapping each [key, value] pair to a new entry.
803
+ * @remarks Time O(N * H), where N is nodes in this tree, and H is height of the new tree during insertion.
804
+ * Space O(N) for the new tree.
919
805
  *
920
- * The `map` function in TypeScript overrides the default map behavior for a binary search tree by
921
- * applying a callback function to each entry and creating a new tree with the results.
922
- * @param callback - A function that will be called for each entry in the BST. It takes four
923
- * arguments: the key, the value (which can be undefined), the index of the entry, and a reference to
924
- * the BST itself.
925
- * @param [options] - The `options` parameter in the `override map` method is of type `BSTOptions<MK,
926
- * MV, MR>`. It is an optional parameter that allows you to specify additional options for the Binary
927
- * Search Tree (BST) being created in the `map` method. These options could include configuration
928
- * @param {any} [thisArg] - The `thisArg` parameter in the `override map` method is used to specify
929
- * the value of `this` that should be used when executing the `callback` function. It allows you to
930
- * set the context or scope in which the callback function will be called. This can be useful when
931
- * you want
932
- * @returns The `map` method is returning a new Binary Search Tree (`BST`) instance with the entries
933
- * transformed by the provided callback function.
806
+ * @template MK - New key type.
807
+ * @template MV - New value type.
808
+ * @template MR - New raw type.
809
+ * @param callback - A function to map each [key, value] pair.
810
+ * @param [options] - Options for the new BST.
811
+ * @param [thisArg] - `this` context for the callback.
812
+ * @returns A new, mapped BST.
934
813
  */
935
- override map(
814
+ override map<MK = K, MV = V, MR extends object = object>(
936
815
  callback: EntryCallback<K, V | undefined, [MK, MV]>,
937
- options?: BSTOptions<MK, MV, MR>,
938
- thisArg?: any
816
+ options?: Partial<BinaryTreeOptions<MK, MV, MR>>,
817
+ thisArg?: unknown
939
818
  ): BST<MK, MV, MR> {
940
- const newTree = new BST<MK, MV, MR>([], options);
819
+ const out = this._createLike<MK, MV, MR>([], options);
941
820
  let index = 0;
821
+ // Iterates in-order
942
822
  for (const [key, value] of this) {
943
- newTree.add(callback.call(thisArg, key, value, index++, this));
823
+ out.add(callback.call(thisArg, key, value, index++, this));
824
+ }
825
+ return out;
826
+ }
827
+
828
+ /**
829
+ * Deletes the first node found that satisfies the predicate.
830
+ * @remarks Performs an in-order traversal. Time O(N) worst-case (O(log N) to find + O(log N) to delete). Space O(log N) for stack.
831
+ *
832
+ * @param predicate - A function to test each [key, value] pair.
833
+ * @returns True if a node was deleted, false otherwise.
834
+ */
835
+ deleteWhere(predicate: (key: K, value: V | undefined, index: number, tree: this) => boolean): boolean {
836
+ const stack: Array<BSTNode<K, V> | null | undefined> = [];
837
+ let cur = this._root as BSTNode<K, V> | null | undefined;
838
+ let index = 0;
839
+
840
+ // In-order traversal to find the node
841
+ while (stack.length > 0 || cur !== undefined) {
842
+ while (cur !== undefined && cur !== null) {
843
+ stack.push(cur);
844
+ cur = cur.left as BSTNode<K, V> | null | undefined;
845
+ }
846
+ const node = stack.pop() as BSTNode<K, V> | undefined;
847
+ if (!node) break;
848
+
849
+ const key = node.key as K;
850
+ const val = node.value as V | undefined;
851
+ if (predicate(key, val, index++, this)) {
852
+ return this._deleteByKey(key); // Found, now delete
853
+ }
854
+ cur = node.right as BSTNode<K, V> | null | undefined;
944
855
  }
945
- return newTree;
856
+ return false;
857
+ }
858
+
859
+ /**
860
+ * (Protected) Creates a new, empty instance of the same BST constructor.
861
+ * @remarks Time O(1)
862
+ *
863
+ * @template TK, TV, TR - Generic types for the new instance.
864
+ * @param [options] - Options for the new BST.
865
+ * @returns A new, empty BST.
866
+ */
867
+ protected override _createInstance<TK = K, TV = V, TR extends object = R>(
868
+ options?: Partial<BSTOptions<TK, TV, TR>>
869
+ ): this {
870
+ const Ctor = this.constructor as unknown as new (
871
+ iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
872
+ opts?: BSTOptions<TK, TV, TR>
873
+ ) => BST<TK, TV, TR>;
874
+ return new Ctor([], { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) }) as unknown as this;
875
+ }
876
+
877
+ /**
878
+ * (Protected) Creates a new instance of the same BST constructor, potentially with different generic types.
879
+ * @remarks Time O(N log N) or O(N^2) (from constructor) due to processing the iterable.
880
+ *
881
+ * @template TK, TV, TR - Generic types for the new instance.
882
+ * @param [iter=[]] - An iterable to populate the new BST.
883
+ * @param [options] - Options for the new BST.
884
+ * @returns A new BST.
885
+ */
886
+ protected override _createLike<TK = K, TV = V, TR extends object = R>(
887
+ iter: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR> = [],
888
+ options?: Partial<BSTOptions<TK, TV, TR>>
889
+ ): BST<TK, TV, TR> {
890
+ const Ctor = this.constructor as unknown as new (
891
+ iter?: Iterable<TK | BSTNode<TK, TV> | [TK | null | undefined, TV | undefined] | null | undefined | TR>,
892
+ opts?: BSTOptions<TK, TV, TR>
893
+ ) => BST<TK, TV, TR>;
894
+ return new Ctor(iter, { ...this._snapshotOptions<TK, TV, TR>(), ...(options ?? {}) });
946
895
  }
947
896
 
948
897
  /**
949
- * Time complexity: O(n)
950
- * Space complexity: O(n)
898
+ * (Protected) Snapshots the current BST's configuration options.
899
+ * @remarks Time O(1)
951
900
  *
952
- * The function `clone` overrides the default cloning behavior to create a deep copy of a tree
953
- * structure.
954
- * @returns The `cloned` object is being returned.
901
+ * @template TK, TV, TR - Generic types for the options.
902
+ * @returns The options object.
955
903
  */
956
- override clone() {
957
- const cloned = this.createTree();
958
- this._clone(cloned);
959
- return cloned;
904
+ protected override _snapshotOptions<TK = K, TV = V, TR extends object = R>(): BSTOptions<TK, TV, TR> {
905
+ return {
906
+ ...super._snapshotOptions<TK, TV, TR>(),
907
+ specifyComparable: this.specifyComparable as BSTOptions<TK, TV, TR>['specifyComparable'],
908
+ isReverse: this.isReverse as BSTOptions<TK, TV, TR>['isReverse']
909
+ };
960
910
  }
961
911
 
962
912
  /**
963
- * Time Complexity: O(1)
964
- * Space Complexity: O(1)
913
+ * (Protected) Converts a key, node, or entry into a standardized [node, value] tuple.
914
+ * @remarks Time O(1)
965
915
  *
966
- * The function overrides a method and converts a key, value pair or entry or raw element to a node.
967
- * @param {K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined } keyNodeOrEntry - A variable that can be of
968
- * type R or K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined . It represents either a key, a node, an entry, or a raw
969
- * element.
970
- * @param {V} [value] - The `value` parameter is an optional value of type `V`. It represents the
971
- * value associated with a key in a key-value pair.
972
- * @returns either a BSTNode<K, V> object or undefined.
916
+ * @param keyNodeOrEntry - The input item.
917
+ * @param [value] - An optional value (used if input is just a key).
918
+ * @returns A tuple of [node, value].
973
919
  */
974
920
  protected override _keyValueNodeOrEntryToNodeAndValue(
975
921
  keyNodeOrEntry: K | BSTNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
976
922
  value?: V
977
923
  ): [OptNode<BSTNode<K, V>>, V | undefined] {
978
924
  const [node, entryValue] = super._keyValueNodeOrEntryToNodeAndValue(keyNodeOrEntry, value);
979
- if (node === null) return [undefined, undefined];
925
+ if (node === null) return [undefined, undefined]; // BST handles null differently (as undefined)
980
926
  return [node, value ?? entryValue];
981
927
  }
982
928
 
983
929
  /**
984
- * Time Complexity: O(1)
985
- * Space Complexity: O(1)
930
+ * (Protected) Sets the root node and clears its parent reference.
931
+ * @remarks Time O(1)
986
932
  *
987
- * The function sets the root of a tree-like structure and updates the parent property of the new
988
- * root.
989
- * @param {OptNode<BSTNode<K, V>>} v - v is a parameter of type BSTNode<K, V> or undefined.
933
+ * @param v - The node to set as root.
990
934
  */
991
935
  protected override _setRoot(v: OptNode<BSTNode<K, V>>) {
992
- if (v) {
993
- v.parent = undefined;
994
- }
936
+ if (v) v.parent = undefined;
995
937
  this._root = v;
996
938
  }
997
939
 
998
940
  /**
999
- * Time Complexity: O(1)
1000
- * Space Complexity: O(1)
941
+ * (Protected) Compares two keys using the tree's comparator and reverse setting.
942
+ * @remarks Time O(1) (or O(C) if `specifyComparable` is used).
1001
943
  *
1002
- * The _compare function compares two values using a specified comparator function and optionally
1003
- * reverses the result.
1004
- * @param {K} a - The parameter `a` is of type `K`, which is used as an input for comparison in the
1005
- * `_compare` method.
1006
- * @param {K} b - The parameter `b` in the `_compare` function is of type `K`.
1007
- * @returns The `_compare` method is returning the result of the ternary expression. If `_isReverse`
1008
- * is true, it returns the negation of the result of calling the `_comparator` function with
1009
- * arguments `a` and `b`. If `_isReverse` is false, it returns the result of calling the
1010
- * `_comparator` function with arguments `a` and `b`.
944
+ * @param a - The first key.
945
+ * @param b - The second key.
946
+ * @returns A number (1, -1, or 0) representing the comparison.
1011
947
  */
1012
948
  protected _compare(a: K, b: K) {
1013
949
  return this._isReverse ? -this._comparator(a, b) : this._comparator(a, b);
1014
950
  }
951
+
952
+ /**
953
+ * (Private) Deletes a node by its key.
954
+ * @remarks Standard BST deletion algorithm. Time O(log N), O(N) worst-case. Space O(1).
955
+ *
956
+ * @param key - The key of the node to delete.
957
+ * @returns True if the node was found and deleted, false otherwise.
958
+ */
959
+ private _deleteByKey(key: K): boolean {
960
+ let node = this._root as BSTNode<K, V> | undefined;
961
+
962
+ // 1. Find the node
963
+ while (node) {
964
+ const cmp = this._compare(node.key, key);
965
+ if (cmp === 0) break;
966
+ node = cmp > 0 ? (node.left as BSTNode<K, V> | undefined) : (node.right as BSTNode<K, V> | undefined);
967
+ }
968
+ if (!node) return false; // Not found
969
+
970
+ // Helper to replace node `u` with node `v`
971
+ const transplant = (u: BSTNode<K, V> | undefined, v: BSTNode<K, V> | undefined) => {
972
+ const p = u?.parent as BSTNode<K, V> | undefined;
973
+ if (!p) {
974
+ this._setRoot(v);
975
+ } else if (p.left === u) {
976
+ p.left = v;
977
+ } else {
978
+ p.right = v;
979
+ }
980
+ if (v) v.parent = p;
981
+ };
982
+
983
+ // Helper to find the minimum node in a subtree
984
+ const minNode = (x: BSTNode<K, V> | undefined): BSTNode<K, V> | undefined => {
985
+ if (!x) return undefined;
986
+ while (x.left !== undefined && x.left !== null) x = x.left as BSTNode<K, V>;
987
+ return x;
988
+ };
989
+
990
+ // 2. Perform deletion
991
+ if (node.left === undefined) {
992
+ // Case 1: No left child
993
+ transplant(node, node.right as BSTNode<K, V> | undefined);
994
+ } else if (node.right === undefined) {
995
+ // Case 2: No right child
996
+ transplant(node, node.left as BSTNode<K, V> | undefined);
997
+ } else {
998
+ // Case 3: Two children
999
+ const succ = minNode(node.right as BSTNode<K, V> | undefined)!; // Find successor
1000
+ if (succ.parent !== node) {
1001
+ transplant(succ, succ.right as BSTNode<K, V> | undefined);
1002
+ succ.right = node.right as BSTNode<K, V> | undefined;
1003
+ if (succ.right) (succ.right as BSTNode<K, V>).parent = succ;
1004
+ }
1005
+ transplant(node, succ);
1006
+ succ.left = node.left as BSTNode<K, V> | undefined;
1007
+ if (succ.left) (succ.left as BSTNode<K, V>).parent = succ;
1008
+ }
1009
+
1010
+ this._size = Math.max(0, ((this as any)._size ?? 0) - 1);
1011
+ return true;
1012
+ }
1015
1013
  }