stack-typed 2.0.5 → 2.1.1

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