min-heap-typed 1.50.0 → 1.50.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/data-structures/base/iterable-base.d.ts +114 -9
  2. package/dist/data-structures/base/iterable-base.js +143 -7
  3. package/dist/data-structures/binary-tree/avl-tree.d.ts +43 -46
  4. package/dist/data-structures/binary-tree/avl-tree.js +68 -71
  5. package/dist/data-structures/binary-tree/binary-tree.d.ts +244 -199
  6. package/dist/data-structures/binary-tree/binary-tree.js +484 -376
  7. package/dist/data-structures/binary-tree/bst.d.ts +54 -74
  8. package/dist/data-structures/binary-tree/bst.js +30 -71
  9. package/dist/data-structures/binary-tree/rb-tree.d.ts +78 -60
  10. package/dist/data-structures/binary-tree/rb-tree.js +84 -89
  11. package/dist/data-structures/binary-tree/tree-multimap.d.ts +37 -56
  12. package/dist/data-structures/binary-tree/tree-multimap.js +64 -85
  13. package/dist/data-structures/graph/abstract-graph.d.ts +1 -0
  14. package/dist/data-structures/graph/abstract-graph.js +3 -0
  15. package/dist/data-structures/graph/directed-graph.d.ts +14 -0
  16. package/dist/data-structures/graph/directed-graph.js +26 -0
  17. package/dist/data-structures/graph/map-graph.d.ts +8 -0
  18. package/dist/data-structures/graph/map-graph.js +14 -0
  19. package/dist/data-structures/graph/undirected-graph.d.ts +16 -0
  20. package/dist/data-structures/graph/undirected-graph.js +25 -0
  21. package/dist/data-structures/hash/hash-map.d.ts +121 -15
  22. package/dist/data-structures/hash/hash-map.js +160 -25
  23. package/dist/data-structures/heap/heap.d.ts +66 -6
  24. package/dist/data-structures/heap/heap.js +66 -6
  25. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +67 -50
  26. package/dist/data-structures/linked-list/doubly-linked-list.js +70 -64
  27. package/dist/data-structures/linked-list/singly-linked-list.d.ts +128 -103
  28. package/dist/data-structures/linked-list/singly-linked-list.js +130 -112
  29. package/dist/data-structures/linked-list/skip-linked-list.d.ts +63 -36
  30. package/dist/data-structures/linked-list/skip-linked-list.js +63 -36
  31. package/dist/data-structures/matrix/matrix.d.ts +35 -4
  32. package/dist/data-structures/matrix/matrix.js +50 -11
  33. package/dist/data-structures/queue/deque.d.ts +49 -19
  34. package/dist/data-structures/queue/deque.js +101 -47
  35. package/dist/data-structures/queue/queue.d.ts +39 -5
  36. package/dist/data-structures/queue/queue.js +47 -5
  37. package/dist/data-structures/stack/stack.d.ts +16 -0
  38. package/dist/data-structures/stack/stack.js +22 -0
  39. package/dist/data-structures/trie/trie.d.ts +38 -1
  40. package/dist/data-structures/trie/trie.js +41 -0
  41. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
  42. package/dist/types/data-structures/hash/hash-map.d.ts +4 -3
  43. package/dist/types/utils/utils.d.ts +1 -0
  44. package/package.json +2 -2
  45. package/src/data-structures/base/iterable-base.ts +172 -19
  46. package/src/data-structures/binary-tree/avl-tree.ts +97 -97
  47. package/src/data-structures/binary-tree/binary-tree.ts +674 -671
  48. package/src/data-structures/binary-tree/bst.ts +89 -131
  49. package/src/data-structures/binary-tree/rb-tree.ts +127 -155
  50. package/src/data-structures/binary-tree/tree-multimap.ts +96 -112
  51. package/src/data-structures/graph/abstract-graph.ts +4 -0
  52. package/src/data-structures/graph/directed-graph.ts +30 -0
  53. package/src/data-structures/graph/map-graph.ts +15 -0
  54. package/src/data-structures/graph/undirected-graph.ts +28 -0
  55. package/src/data-structures/hash/hash-map.ts +175 -34
  56. package/src/data-structures/heap/heap.ts +66 -6
  57. package/src/data-structures/linked-list/doubly-linked-list.ts +72 -66
  58. package/src/data-structures/linked-list/singly-linked-list.ts +132 -114
  59. package/src/data-structures/linked-list/skip-linked-list.ts +63 -37
  60. package/src/data-structures/matrix/matrix.ts +52 -12
  61. package/src/data-structures/queue/deque.ts +108 -49
  62. package/src/data-structures/queue/queue.ts +51 -5
  63. package/src/data-structures/stack/stack.ts +24 -0
  64. package/src/data-structures/trie/trie.ts +45 -1
  65. package/src/types/data-structures/binary-tree/binary-tree.ts +1 -1
  66. package/src/types/data-structures/hash/hash-map.ts +4 -3
  67. package/src/types/utils/utils.ts +2 -0
@@ -28,46 +28,74 @@ import { IterableEntryBase } from '../base';
28
28
  /**
29
29
  * Represents a node in a binary tree.
30
30
  * @template V - The type of data stored in the node.
31
- * @template N - The type of the family relationship in the binary tree.
31
+ * @template NODE - The type of the family relationship in the binary tree.
32
32
  */
33
33
  export class BinaryTreeNode<
34
34
  K = any,
35
35
  V = any,
36
- N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>
36
+ NODE extends BinaryTreeNode<K, V, NODE> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>
37
37
  > {
38
38
  key: K;
39
39
 
40
40
  value?: V;
41
41
 
42
- parent?: N;
42
+ parent?: NODE;
43
43
 
44
+ /**
45
+ * The constructor function initializes an object with a key and an optional value.
46
+ * @param {K} key - The "key" parameter is of type K, which represents the type of the key for the
47
+ * constructor. It is used to set the value of the "key" property of the object being created.
48
+ * @param {V} [value] - The "value" parameter is an optional parameter of type V. It represents the
49
+ * value associated with the key in the constructor.
50
+ */
44
51
  constructor(key: K, value?: V) {
45
52
  this.key = key;
46
53
  this.value = value;
47
54
  }
48
55
 
49
- protected _left?: N | null;
56
+ protected _left?: NODE | null;
50
57
 
51
- get left(): N | null | undefined {
58
+ /**
59
+ * The function returns the value of the `_left` property, which can be of type `NODE`, `null`, or
60
+ * `undefined`.
61
+ * @returns The left node of the current node is being returned. It can be either a NODE object,
62
+ * null, or undefined.
63
+ */
64
+ get left(): NODE | null | undefined {
52
65
  return this._left;
53
66
  }
54
67
 
55
- set left(v: N | null | undefined) {
68
+ /**
69
+ * The function sets the left child of a node and updates its parent reference.
70
+ * @param {NODE | null | undefined} v - The parameter `v` can be of type `NODE`, `null`, or
71
+ * `undefined`.
72
+ */
73
+ set left(v: NODE | null | undefined) {
56
74
  if (v) {
57
- v.parent = this as unknown as N;
75
+ v.parent = this as unknown as NODE;
58
76
  }
59
77
  this._left = v;
60
78
  }
61
79
 
62
- protected _right?: N | null;
80
+ protected _right?: NODE | null;
63
81
 
64
- get right(): N | null | undefined {
82
+ /**
83
+ * The function returns the right node of a binary tree or null if it doesn't exist.
84
+ * @returns The method is returning the value of the `_right` property, which can be a `NODE` object,
85
+ * `null`, or `undefined`.
86
+ */
87
+ get right(): NODE | null | undefined {
65
88
  return this._right;
66
89
  }
67
90
 
68
- set right(v: N | null | undefined) {
91
+ /**
92
+ * The function sets the right child of a node and updates its parent.
93
+ * @param {NODE | null | undefined} v - The parameter `v` can be of type `NODE`, `null`, or
94
+ * `undefined`.
95
+ */
96
+ set right(v: NODE | null | undefined) {
69
97
  if (v) {
70
- v.parent = this as unknown as N;
98
+ v.parent = this as unknown as NODE;
71
99
  }
72
100
  this._right = v;
73
101
  }
@@ -77,7 +105,7 @@ export class BinaryTreeNode<
77
105
  * @returns {FamilyPosition} - The family position of the node.
78
106
  */
79
107
  get familyPosition(): FamilyPosition {
80
- const that = this as unknown as N;
108
+ const that = this as unknown as NODE;
81
109
  if (!this.parent) {
82
110
  return this.left || this.right ? FamilyPosition.ROOT : FamilyPosition.ISOLATED;
83
111
  }
@@ -103,11 +131,11 @@ export class BinaryTreeNode<
103
131
  export class BinaryTree<
104
132
  K = any,
105
133
  V = any,
106
- N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>,
107
- TREE extends BinaryTree<K, V, N, TREE> = BinaryTree<K, V, N, BinaryTreeNested<K, V, N>>
134
+ NODE extends BinaryTreeNode<K, V, NODE> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>,
135
+ TREE extends BinaryTree<K, V, NODE, TREE> = BinaryTree<K, V, NODE, BinaryTreeNested<K, V, NODE>>
108
136
  >
109
137
  extends IterableEntryBase<K, V | undefined>
110
- implements IBinaryTree<K, V, N, TREE> {
138
+ implements IBinaryTree<K, V, NODE, TREE> {
111
139
  iterationType = IterationType.ITERATIVE;
112
140
 
113
141
  /**
@@ -119,7 +147,7 @@ export class BinaryTree<
119
147
  * `Partial<BinaryTreeOptions>`, which means that not all properties of `BinaryTreeOptions` are
120
148
  * required.
121
149
  */
122
- constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, N>> = [], options?: BinaryTreeOptions<K>) {
150
+ constructor(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>> = [], options?: BinaryTreeOptions<K>) {
123
151
  super();
124
152
  if (options) {
125
153
  const { iterationType, extractor } = options;
@@ -134,18 +162,31 @@ export class BinaryTree<
134
162
 
135
163
  protected _extractor = (key: K) => Number(key);
136
164
 
165
+ /**
166
+ * The function returns the value of the `_extractor` property.
167
+ * @returns The `_extractor` property is being returned.
168
+ */
137
169
  get extractor() {
138
170
  return this._extractor;
139
171
  }
140
172
 
141
- protected _root?: N | null;
173
+ protected _root?: NODE | null;
142
174
 
143
- get root(): N | null | undefined {
175
+ /**
176
+ * The function returns the root node, which can be of type NODE, null, or undefined.
177
+ * @returns The method is returning the value of the `_root` property, which can be of type `NODE`,
178
+ * `null`, or `undefined`.
179
+ */
180
+ get root(): NODE | null | undefined {
144
181
  return this._root;
145
182
  }
146
183
 
147
184
  protected _size: number;
148
185
 
186
+ /**
187
+ * The function returns the size of an object.
188
+ * @returns The size of the object, which is a number.
189
+ */
149
190
  get size(): number {
150
191
  return this._size;
151
192
  }
@@ -154,10 +195,10 @@ export class BinaryTree<
154
195
  * Creates a new instance of BinaryTreeNode with the given key and value.
155
196
  * @param {K} key - The key for the new node.
156
197
  * @param {V} value - The value for the new node.
157
- * @returns {N} - The newly created BinaryTreeNode.
198
+ * @returns {NODE} - The newly created BinaryTreeNode.
158
199
  */
159
- createNode(key: K, value?: V): N {
160
- return new BinaryTreeNode<K, V, N>(key, value) as N;
200
+ createNode(key: K, value?: V): NODE {
201
+ return new BinaryTreeNode<K, V, NODE>(key, value) as NODE;
161
202
  }
162
203
 
163
204
  /**
@@ -168,21 +209,21 @@ export class BinaryTree<
168
209
  * @returns a new instance of a binary tree.
169
210
  */
170
211
  createTree(options?: Partial<BinaryTreeOptions<K>>): TREE {
171
- return new BinaryTree<K, V, N, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
212
+ return new BinaryTree<K, V, NODE, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
172
213
  }
173
214
 
174
215
  /**
175
- * The function `exemplarToNode` converts an keyOrNodeOrEntry object into a node object.
176
- * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry<K, V, N>`.
216
+ * The function `keyValueOrEntryToNode` converts an keyOrNodeOrEntry object into a node object.
217
+ * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is of type `KeyOrNodeOrEntry<K, V, NODE>`.
177
218
  * @param {V} [value] - The `value` parameter is an optional value that can be passed to the
178
- * `exemplarToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If no value
219
+ * `keyValueOrEntryToNode` function. It represents the value associated with the keyOrNodeOrEntry node. If no value
179
220
  * is provided, it will be `undefined`.
180
- * @returns a value of type N (node), or null, or undefined.
221
+ * @returns a value of type NODE (node), or null, or undefined.
181
222
  */
182
- exemplarToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, N>, value?: V): N | null | undefined {
223
+ keyValueOrEntryToNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V): NODE | null | undefined {
183
224
  if (keyOrNodeOrEntry === undefined) return;
184
225
 
185
- let node: N | null | undefined;
226
+ let node: NODE | null | undefined;
186
227
  if (keyOrNodeOrEntry === null) {
187
228
  node = null;
188
229
  } else if (this.isEntry(keyOrNodeOrEntry)) {
@@ -215,7 +256,7 @@ export class BinaryTree<
215
256
  *
216
257
  * The function `ensureNode` returns the node corresponding to the given key if it is a valid node
217
258
  * key, otherwise it returns the key itself.
218
- * @param {K | N | null | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `N`,
259
+ * @param {K | NODE | null | undefined} keyOrNodeOrEntry - The `key` parameter can be of type `K`, `NODE`,
219
260
  * `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
220
261
  * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
221
262
  * type of iteration to be used when searching for a node by key. It has a default value of
@@ -224,10 +265,10 @@ export class BinaryTree<
224
265
  * itself if it is not a valid node key.
225
266
  */
226
267
  ensureNode(
227
- keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, N>,
268
+ keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>,
228
269
  iterationType = IterationType.ITERATIVE
229
- ): N | null | undefined {
230
- let res: N | null | undefined;
270
+ ): NODE | null | undefined {
271
+ let res: NODE | null | undefined;
231
272
  if (this.isRealNode(keyOrNodeOrEntry)) {
232
273
  res = keyOrNodeOrEntry;
233
274
  } else if (this.isEntry(keyOrNodeOrEntry)) {
@@ -242,35 +283,30 @@ export class BinaryTree<
242
283
 
243
284
  /**
244
285
  * The function "isNode" checks if an keyOrNodeOrEntry is an instance of the BinaryTreeNode class.
245
- * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry<K, V,N>`.
246
- * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the class N.
286
+ * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter is a variable of type `KeyOrNodeOrEntry<K, V,NODE>`.
287
+ * @returns a boolean value indicating whether the keyOrNodeOrEntry is an instance of the class NODE.
247
288
  */
248
- isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, N>): keyOrNodeOrEntry is N {
289
+ isNode(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>): keyOrNodeOrEntry is NODE {
249
290
  return keyOrNodeOrEntry instanceof BinaryTreeNode;
250
291
  }
251
292
 
252
293
  /**
253
294
  * The function checks if a given value is an entry in a binary tree node.
254
- * @param keyOrNodeOrEntry - KeyOrNodeOrEntry<K, V,N> - A generic type representing a node in a binary tree. It has
255
- * two type parameters V and N, representing the value and node type respectively.
295
+ * @param keyOrNodeOrEntry - KeyOrNodeOrEntry<K, V,NODE> - A generic type representing a node in a binary tree. It has
296
+ * two type parameters V and NODE, representing the value and node type respectively.
256
297
  * @returns a boolean value.
257
298
  */
258
- isEntry(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, N>): keyOrNodeOrEntry is BTNEntry<K, V> {
299
+ isEntry(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>): keyOrNodeOrEntry is BTNEntry<K, V> {
259
300
  return Array.isArray(keyOrNodeOrEntry) && keyOrNodeOrEntry.length === 2;
260
301
  }
261
302
 
262
- /**
263
- * Time complexity: O(n)
264
- * Space complexity: O(log n)
265
- */
266
-
267
303
  /**
268
304
  * The function checks if a given node is a real node by verifying if it is an instance of
269
305
  * BinaryTreeNode and its key is not NaN.
270
306
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
271
307
  * @returns a boolean value.
272
308
  */
273
- isRealNode(node: KeyOrNodeOrEntry<K, V, N>): node is N {
309
+ isRealNode(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE {
274
310
  return node instanceof BinaryTreeNode && String(node.key) !== 'NaN';
275
311
  }
276
312
 
@@ -279,7 +315,7 @@ export class BinaryTree<
279
315
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
280
316
  * @returns a boolean value.
281
317
  */
282
- isNIL(node: KeyOrNodeOrEntry<K, V, N>) {
318
+ isNIL(node: KeyOrNodeOrEntry<K, V, NODE>) {
283
319
  return node instanceof BinaryTreeNode && String(node.key) === 'NaN';
284
320
  }
285
321
 
@@ -288,27 +324,27 @@ export class BinaryTree<
288
324
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
289
325
  * @returns a boolean value.
290
326
  */
291
- isNodeOrNull(node: KeyOrNodeOrEntry<K, V, N>): node is N | null {
327
+ isNodeOrNull(node: KeyOrNodeOrEntry<K, V, NODE>): node is NODE | null {
292
328
  return this.isRealNode(node) || node === null;
293
329
  }
294
330
 
295
331
  /**
296
- * Time Complexity O(log n) - O(n)
332
+ * Time Complexity O(n)
297
333
  * Space Complexity O(1)
298
334
  */
299
335
 
300
336
  /**
301
- * Time Complexity O(log n) - O(n)
337
+ * Time Complexity O(n)
302
338
  * Space Complexity O(1)
303
339
  *
304
340
  * The `add` function adds a new node to a binary tree, either by creating a new node or replacing an
305
341
  * existing node with the same key.
306
342
  * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following:
307
343
  * @param {V} [value] - The value to be inserted into the binary tree.
308
- * @returns The function `add` returns either a node (`N`), `null`, or `undefined`.
344
+ * @returns The function `add` returns either a node (`NODE`), `null`, or `undefined`.
309
345
  */
310
- add(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, N>, value?: V): boolean {
311
- const newNode = this.exemplarToNode(keyOrNodeOrEntry, value);
346
+ add(keyOrNodeOrEntry: KeyOrNodeOrEntry<K, V, NODE>, value?: V): boolean {
347
+ const newNode = this.keyValueOrEntryToNode(keyOrNodeOrEntry, value);
312
348
  if (newNode === undefined) return false;
313
349
 
314
350
  // If the tree is empty, directly set the new node as the root node
@@ -318,8 +354,8 @@ export class BinaryTree<
318
354
  return true;
319
355
  }
320
356
 
321
- const queue = new Queue<N>([this.root]);
322
- let potentialParent: N | undefined; // Record the parent node of the potential insertion location
357
+ const queue = new Queue<NODE>([this.root]);
358
+ let potentialParent: NODE | undefined; // Record the parent node of the potential insertion location
323
359
 
324
360
  while (queue.size > 0) {
325
361
  const cur = queue.shift();
@@ -361,22 +397,22 @@ export class BinaryTree<
361
397
  }
362
398
 
363
399
  /**
364
- * Time Complexity: O(k log n) - O(k * n)
400
+ * Time Complexity: O(k * n)
365
401
  * Space Complexity: O(1)
366
402
  * Comments: The time complexity for adding a node depends on the depth of the tree. In the best case (when the tree is empty), it's O(1). In the worst case (when the tree is a degenerate tree), it's O(n). The space complexity is constant.
367
403
  */
368
404
 
369
405
  /**
370
- * Time Complexity: O(k log n) - O(k * n)
406
+ * Time Complexity: O(k * n)
371
407
  * Space Complexity: O(1)
372
408
  *
373
409
  * The `addMany` function takes in a collection of keysOrNodesOrEntries and an optional collection of values, and
374
410
  * adds each node with its corresponding value to the data structure.
375
411
  * @param keysOrNodesOrEntries - An iterable collection of KeyOrNodeOrEntry objects.
376
412
  * @param [values] - An optional iterable of values that will be assigned to each node being added.
377
- * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
413
+ * @returns The function `addMany` returns an array of `NODE`, `null`, or `undefined` values.
378
414
  */
379
- addMany(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, N>>, values?: Iterable<V | undefined>): boolean[] {
415
+ addMany(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>>, values?: Iterable<V | undefined>): boolean[] {
380
416
  // TODO not sure addMany not be run multi times
381
417
  const inserted: boolean[] = [];
382
418
 
@@ -413,30 +449,32 @@ export class BinaryTree<
413
449
  *
414
450
  * The `refill` function clears the current data and adds new key-value pairs to the data structure.
415
451
  * @param keysOrNodesOrEntries - An iterable containing keys, nodes, or entries. These can be of type
416
- * KeyOrNodeOrEntry<K, V, N>.
452
+ * KeyOrNodeOrEntry<K, V, NODE>.
417
453
  * @param [values] - The `values` parameter is an optional iterable that contains the values to be
418
454
  * associated with the keys or nodes or entries in the `keysOrNodesOrEntries` parameter. If provided,
419
455
  * the values will be associated with the corresponding keys or nodes or entries in the
420
456
  * `keysOrNodesOrEntries` iterable
421
457
  */
422
- refill(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, N>>, values?: Iterable<V | undefined>): void {
458
+ refill(keysOrNodesOrEntries: Iterable<KeyOrNodeOrEntry<K, V, NODE>>, values?: Iterable<V | undefined>): void {
423
459
  this.clear();
424
460
  this.addMany(keysOrNodesOrEntries, values);
425
461
  }
426
462
 
427
- /**
428
- * Time Complexity: O(k * n)
429
- * Space Complexity: O(1)
430
- * "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
431
- */
432
-
433
- delete<C extends BTNCallback<N, K>>(identifier: K, callback?: C): BinaryTreeDeleteResult<N>[];
463
+ delete<C extends BTNCallback<NODE, K>>(identifier: K, callback?: C): BinaryTreeDeleteResult<NODE>[];
434
464
 
435
- delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BinaryTreeDeleteResult<N>[];
465
+ delete<C extends BTNCallback<NODE, NODE>>(
466
+ identifier: NODE | null | undefined,
467
+ callback?: C
468
+ ): BinaryTreeDeleteResult<NODE>[];
436
469
 
437
- delete<C extends BTNCallback<N>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeleteResult<N>[];
470
+ delete<C extends BTNCallback<NODE>>(identifier: ReturnType<C>, callback: C): BinaryTreeDeleteResult<NODE>[];
438
471
 
439
472
  /**
473
+ * Time Complexity: O(n)
474
+ * Space Complexity: O(1)
475
+ * /
476
+
477
+ /**
440
478
  * Time Complexity: O(n)
441
479
  * Space Complexity: O(1)
442
480
  *
@@ -449,13 +487,13 @@ export class BinaryTree<
449
487
  * @param {C} callback - The `callback` parameter is a function that is used to determine the
450
488
  * identifier of the node to be deleted. It is optional and has a default value of
451
489
  * `this._defaultOneParamCallback`. The `callback` function should return the identifier of the node.
452
- * @returns an array of `BinaryTreeDeleteResult<N>`.
490
+ * @returns an array of `BinaryTreeDeleteResult<NODE>`.
453
491
  */
454
- delete<C extends BTNCallback<N>>(
492
+ delete<C extends BTNCallback<NODE>>(
455
493
  identifier: ReturnType<C> | null | undefined,
456
494
  callback: C = this._defaultOneParamCallback as C
457
- ): BinaryTreeDeleteResult<N>[] {
458
- const deletedResult: BinaryTreeDeleteResult<N>[] = [];
495
+ ): BinaryTreeDeleteResult<NODE>[] {
496
+ const deletedResult: BinaryTreeDeleteResult<NODE>[] = [];
459
497
  if (!this.root) return deletedResult;
460
498
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
461
499
  callback = (node => node) as C;
@@ -463,240 +501,75 @@ export class BinaryTree<
463
501
  const curr = this.getNode(identifier, callback);
464
502
  if (!curr) return deletedResult;
465
503
 
466
- const parent: N | null | undefined = curr?.parent ? curr.parent : null;
467
- let needBalanced: N | null | undefined = undefined;
468
- let orgCurrent: N | undefined = curr;
469
-
470
- if (!curr.left) {
471
- if (!parent) {
472
- // Handle the case when there's only one root node
473
- this._setRoot(null);
474
- } else {
475
- const { familyPosition: fp } = curr;
476
- if (fp === FamilyPosition.LEFT || fp === FamilyPosition.ROOT_LEFT) {
477
- parent.left = curr.right;
478
- } else if (fp === FamilyPosition.RIGHT || fp === FamilyPosition.ROOT_RIGHT) {
479
- parent.right = curr.right;
504
+ const parent: NODE | undefined = curr?.parent;
505
+ let needBalanced: NODE | undefined;
506
+ let orgCurrent: NODE | undefined = curr;
507
+
508
+ if (!curr.left && !curr.right && !parent) {
509
+ this._setRoot(undefined);
510
+ } else if (curr.left) {
511
+ const leftSubTreeRightMost = this.getRightMost(curr.left);
512
+ if (leftSubTreeRightMost) {
513
+ const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
514
+ orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
515
+ if (parentOfLeftSubTreeMax) {
516
+ if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
517
+ parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
518
+ else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left;
519
+ needBalanced = parentOfLeftSubTreeMax;
480
520
  }
481
- needBalanced = parent;
482
521
  }
483
- } else {
484
- if (curr.left) {
485
- const leftSubTreeRightMost = this.getRightMost(curr.left);
486
- if (leftSubTreeRightMost) {
487
- const parentOfLeftSubTreeMax = leftSubTreeRightMost.parent;
488
- orgCurrent = this._swapProperties(curr, leftSubTreeRightMost);
489
- if (parentOfLeftSubTreeMax) {
490
- if (parentOfLeftSubTreeMax.right === leftSubTreeRightMost)
491
- parentOfLeftSubTreeMax.right = leftSubTreeRightMost.left;
492
- else parentOfLeftSubTreeMax.left = leftSubTreeRightMost.left;
493
- needBalanced = parentOfLeftSubTreeMax;
494
- }
495
- }
522
+ } else if (parent) {
523
+ const { familyPosition: fp } = curr;
524
+ if (fp === FamilyPosition.LEFT || fp === FamilyPosition.ROOT_LEFT) {
525
+ parent.left = curr.right;
526
+ } else if (fp === FamilyPosition.RIGHT || fp === FamilyPosition.ROOT_RIGHT) {
527
+ parent.right = curr.right;
496
528
  }
529
+ needBalanced = parent;
530
+ } else {
531
+ this._setRoot(curr.right);
532
+ curr.right = undefined;
497
533
  }
534
+
498
535
  this._size = this.size - 1;
499
536
 
500
537
  deletedResult.push({ deleted: orgCurrent, needBalanced });
501
538
  return deletedResult;
502
539
  }
503
540
 
504
- /**
505
- * Time Complexity: O(n)
506
- * Space Complexity: O(1)
507
- */
508
-
509
- /**
510
- * Time Complexity: O(n)
511
- * Space Complexity: O(1)
512
- *
513
- * The function calculates the depth of a given node in a binary tree.
514
- * @param {K | N | null | undefined} dist - The `dist` parameter represents the node in
515
- * the binary tree whose depth we want to find. It can be of type `K`, `N`, `null`, or
516
- * `undefined`.
517
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
518
- * from which we want to calculate the depth. It can be either a `K` (binary tree node key) or
519
- * `N` (binary tree node) or `null` or `undefined`. If no value is provided for `beginRoot
520
- * @returns the depth of the `dist` relative to the `beginRoot`.
521
- */
522
- getDepth(dist: KeyOrNodeOrEntry<K, V, N>, beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root): number {
523
- dist = this.ensureNode(dist);
524
- beginRoot = this.ensureNode(beginRoot);
525
- let depth = 0;
526
- while (dist?.parent) {
527
- if (dist === beginRoot) {
528
- return depth;
529
- }
530
- depth++;
531
- dist = dist.parent;
532
- }
533
- return depth;
534
- }
535
-
536
- /**
537
- * Time Complexity: O(n)
538
- * Space Complexity: O(1)
539
- */
540
-
541
- /**
542
- * Time Complexity: O(n)
543
- * Space Complexity: O(log n)
544
- *
545
- * The function `getHeight` calculates the maximum height of a binary tree using either recursive or
546
- * iterative traversal.
547
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
548
- * starting node of the binary tree from which we want to calculate the height. It can be of type
549
- * `K`, `N`, `null`, or `undefined`. If not provided, it defaults to `this.root`.
550
- * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the
551
- * height of the tree using a recursive approach or an iterative approach. It can have two possible
552
- * values:
553
- * @returns the height of the binary tree.
554
- */
555
- getHeight(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root, iterationType = this.iterationType): number {
556
- beginRoot = this.ensureNode(beginRoot);
557
- if (!beginRoot) return -1;
558
-
559
- if (iterationType === IterationType.RECURSIVE) {
560
- const _getMaxHeight = (cur: N | null | undefined): number => {
561
- if (!cur) return -1;
562
- const leftHeight = _getMaxHeight(cur.left);
563
- const rightHeight = _getMaxHeight(cur.right);
564
- return Math.max(leftHeight, rightHeight) + 1;
565
- };
566
-
567
- return _getMaxHeight(beginRoot);
568
- } else {
569
- const stack: { node: N; depth: number }[] = [{ node: beginRoot, depth: 0 }];
570
- let maxHeight = 0;
571
-
572
- while (stack.length > 0) {
573
- const { node, depth } = stack.pop()!;
574
-
575
- if (node.left) stack.push({ node: node.left, depth: depth + 1 });
576
- if (node.right) stack.push({ node: node.right, depth: depth + 1 });
577
-
578
- maxHeight = Math.max(maxHeight, depth);
579
- }
580
-
581
- return maxHeight;
582
- }
583
- }
584
-
585
- /**
586
- * Time Complexity: O(n)
587
- * Space Complexity: O(log n)
588
- * Best Case - O(log n) (when using recursive iterationType), Worst Case - O(n) (when using iterative iterationType)
589
- */
590
-
591
- /**
592
- * Time Complexity: O(n)
593
- * Space Complexity: O(log n)
594
- *
595
- * The `getMinHeight` function calculates the minimum height of a binary tree using either a
596
- * recursive or iterative approach.
597
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
598
- * starting node of the binary tree from which we want to calculate the minimum height. It can be of
599
- * type `K`, `N`, `null`, or `undefined`. If no value is provided, it defaults to `this.root`.
600
- * @param iterationType - The `iterationType` parameter is used to determine the method of iteration
601
- * to calculate the minimum height of a binary tree. It can have two possible values:
602
- * @returns The function `getMinHeight` returns the minimum height of a binary tree.
603
- */
604
- getMinHeight(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root, iterationType = this.iterationType): number {
605
- beginRoot = this.ensureNode(beginRoot);
606
- if (!beginRoot) return -1;
607
-
608
- if (iterationType === IterationType.RECURSIVE) {
609
- const _getMinHeight = (cur: N | null | undefined): number => {
610
- if (!cur) return 0;
611
- if (!cur.left && !cur.right) return 0;
612
- const leftMinHeight = _getMinHeight(cur.left);
613
- const rightMinHeight = _getMinHeight(cur.right);
614
- return Math.min(leftMinHeight, rightMinHeight) + 1;
615
- };
616
-
617
- return _getMinHeight(beginRoot);
618
- } else {
619
- const stack: N[] = [];
620
- let node: N | null | undefined = beginRoot,
621
- last: N | null | undefined = null;
622
- const depths: Map<N, number> = new Map();
623
-
624
- while (stack.length > 0 || node) {
625
- if (node) {
626
- stack.push(node);
627
- node = node.left;
628
- } else {
629
- node = stack[stack.length - 1];
630
- if (!node.right || last === node.right) {
631
- node = stack.pop();
632
- if (node) {
633
- const leftMinHeight = node.left ? depths.get(node.left) ?? -1 : -1;
634
- const rightMinHeight = node.right ? depths.get(node.right) ?? -1 : -1;
635
- depths.set(node, 1 + Math.min(leftMinHeight, rightMinHeight));
636
- last = node;
637
- node = null;
638
- }
639
- } else node = node.right;
640
- }
641
- }
642
-
643
- return depths.get(beginRoot) ?? -1;
644
- }
645
- }
646
-
647
- /**
648
- * Time Complexity: O(n)
649
- * Space Complexity: O(log n)
650
- * Best Case - O(log n) (when using recursive iterationType), Worst Case - O(n) (when using iterative iterationType)
651
- */
652
-
653
- /**
654
- * Time Complexity: O(n)
655
- * Space Complexity: O(log n)
656
- *
657
- * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the
658
- * height of the tree.
659
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
660
- * for calculating the height and minimum height of a binary tree. It can be either a `K` (a key
661
- * value of a binary tree node), `N` (a node of a binary tree), `null`, or `undefined`. If
662
- * @returns a boolean value.
663
- */
664
- isPerfectlyBalanced(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root): boolean {
665
- return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
666
- }
667
-
668
- /**
669
- * Time Complexity: O(n)
670
- * Space Complexity: O(log n)
671
- */
672
-
673
- getNodes<C extends BTNCallback<N, K>>(
541
+ getNodes<C extends BTNCallback<NODE, K>>(
674
542
  identifier: K,
675
543
  callback?: C,
676
544
  onlyOne?: boolean,
677
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
545
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
678
546
  iterationType?: IterationType
679
- ): N[];
547
+ ): NODE[];
680
548
 
681
- getNodes<C extends BTNCallback<N, N>>(
682
- identifier: N | null | undefined,
549
+ getNodes<C extends BTNCallback<NODE, NODE>>(
550
+ identifier: NODE | null | undefined,
683
551
  callback?: C,
684
552
  onlyOne?: boolean,
685
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
553
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
686
554
  iterationType?: IterationType
687
- ): N[];
555
+ ): NODE[];
688
556
 
689
- getNodes<C extends BTNCallback<N>>(
557
+ getNodes<C extends BTNCallback<NODE>>(
690
558
  identifier: ReturnType<C>,
691
559
  callback: C,
692
560
  onlyOne?: boolean,
693
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
561
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
694
562
  iterationType?: IterationType
695
- ): N[];
563
+ ): NODE[];
696
564
 
697
565
  /**
698
566
  * Time Complexity: O(n)
699
- * Space Complexity: O(log n).
567
+ * Space Complexity: O(k + log n)
568
+ */
569
+
570
+ /**
571
+ * Time Complexity: O(n)
572
+ * Space Complexity: O(k + log n).
700
573
  *
701
574
  * The function `getNodes` retrieves nodes from a binary tree based on a given identifier and
702
575
  * callback function.
@@ -704,7 +577,7 @@ export class BinaryTree<
704
577
  * that you want to search for in the binary tree. It can be of any type that is returned by the
705
578
  * callback function `C`. It can also be `null` or `undefined` if you don't want to search for a
706
579
  * specific value.
707
- * @param {C} callback - The `callback` parameter is a function that takes a node of type `N` as
580
+ * @param {C} callback - The `callback` parameter is a function that takes a node of type `NODE` as
708
581
  * input and returns a value of type `C`. It is used to determine if a node matches the given
709
582
  * identifier. If no callback is provided, the `_defaultOneParamCallback` function is used as the
710
583
  * default
@@ -712,29 +585,29 @@ export class BinaryTree<
712
585
  * matches the identifier. If set to true, the function will stop iterating once it finds a matching
713
586
  * node and return that node. If set to false (default), the function will continue iterating and
714
587
  * return all nodes that match the identifier.
715
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
588
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
716
589
  * starting node for the traversal. It can be either a key, a node object, or `null`/`undefined`. If
717
590
  * it is `null` or `undefined`, an empty array will be returned.
718
591
  * @param iterationType - The `iterationType` parameter determines the type of iteration used to
719
592
  * traverse the binary tree. It can have two possible values:
720
- * @returns an array of nodes of type `N`.
593
+ * @returns an array of nodes of type `NODE`.
721
594
  */
722
- getNodes<C extends BTNCallback<N>>(
595
+ getNodes<C extends BTNCallback<NODE>>(
723
596
  identifier: ReturnType<C> | null | undefined,
724
597
  callback: C = this._defaultOneParamCallback as C,
725
598
  onlyOne = false,
726
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
599
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
727
600
  iterationType = this.iterationType
728
- ): N[] {
601
+ ): NODE[] {
729
602
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
730
603
  callback = (node => node) as C;
731
604
  beginRoot = this.ensureNode(beginRoot);
732
605
  if (!beginRoot) return [];
733
606
 
734
- const ans: N[] = [];
607
+ const ans: NODE[] = [];
735
608
 
736
609
  if (iterationType === IterationType.RECURSIVE) {
737
- const _traverse = (cur: N) => {
610
+ const _traverse = (cur: NODE) => {
738
611
  if (callback(cur) === identifier) {
739
612
  ans.push(cur);
740
613
  if (onlyOne) return;
@@ -746,7 +619,7 @@ export class BinaryTree<
746
619
 
747
620
  _traverse(beginRoot);
748
621
  } else {
749
- const queue = new Queue<N>([beginRoot]);
622
+ const queue = new Queue<NODE>([beginRoot]);
750
623
  while (queue.size > 0) {
751
624
  const cur = queue.shift();
752
625
  if (cur) {
@@ -763,91 +636,32 @@ export class BinaryTree<
763
636
  return ans;
764
637
  }
765
638
 
766
- /**
767
- * Time Complexity: O(n)
768
- * Space Complexity: O(log n).
769
- */
770
-
771
- has<C extends BTNCallback<N, K>>(
639
+ getNode<C extends BTNCallback<NODE, K>>(
772
640
  identifier: K,
773
641
  callback?: C,
774
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
642
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
775
643
  iterationType?: IterationType
776
- ): boolean;
644
+ ): NODE | null | undefined;
777
645
 
778
- has<C extends BTNCallback<N, N>>(
779
- identifier: N | null | undefined,
646
+ getNode<C extends BTNCallback<NODE, NODE>>(
647
+ identifier: NODE | null | undefined,
780
648
  callback?: C,
781
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
649
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
782
650
  iterationType?: IterationType
783
- ): boolean;
651
+ ): NODE | null | undefined;
784
652
 
785
- has<C extends BTNCallback<N>>(
786
- identifier: ReturnType<C> | null | undefined,
653
+ getNode<C extends BTNCallback<NODE>>(
654
+ identifier: ReturnType<C>,
787
655
  callback: C,
788
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
656
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
789
657
  iterationType?: IterationType
790
- ): boolean;
791
-
792
- /**
793
- * Time Complexity: O(n)
794
- * Space Complexity: O(log n).
795
- *
796
- * The function checks if a Binary Tree Node with a specific identifier exists in the tree.
797
- * @param {ReturnType<C> | null | undefined} identifier - The `identifier` parameter is the value
798
- * that you want to search for in the binary tree. It can be of any type that is returned by the
799
- * callback function `C`. It can also be `null` or `undefined` if you don't want to specify a
800
- * specific identifier.
801
- * @param {C} callback - The `callback` parameter is a function that will be called for each node in
802
- * the binary tree. It is used to filter the nodes based on certain conditions. The `callback`
803
- * function should return a boolean value indicating whether the node should be included in the
804
- * result or not.
805
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
806
- * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a
807
- * node in the binary tree), a node object (`N`), or `null`/`undefined` to start the search from
808
- * @param iterationType - The `iterationType` parameter is a variable that determines the type of
809
- * iteration to be performed on the binary tree. It is used to specify whether the iteration should
810
- * be performed in a pre-order, in-order, or post-order manner.
811
- * @returns a boolean value.
812
- */
813
- has<C extends BTNCallback<N>>(
814
- identifier: ReturnType<C> | null | undefined,
815
- callback: C = this._defaultOneParamCallback as C,
816
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
817
- iterationType = this.iterationType
818
- ): boolean {
819
- if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
820
- callback = (node => node) as C;
821
-
822
- return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
823
- }
658
+ ): NODE | null | undefined;
824
659
 
825
660
  /**
826
661
  * Time Complexity: O(n)
827
662
  * Space Complexity: O(log n).
828
663
  */
829
664
 
830
- getNode<C extends BTNCallback<N, K>>(
831
- identifier: K,
832
- callback?: C,
833
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
834
- iterationType?: IterationType
835
- ): N | null | undefined;
836
-
837
- getNode<C extends BTNCallback<N, N>>(
838
- identifier: N | null | undefined,
839
- callback?: C,
840
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
841
- iterationType?: IterationType
842
- ): N | null | undefined;
843
-
844
- getNode<C extends BTNCallback<N>>(
845
- identifier: ReturnType<C>,
846
- callback: C,
847
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
848
- iterationType?: IterationType
849
- ): N | null | undefined;
850
-
851
665
  /**
852
666
  * Time Complexity: O(n)
853
667
  * Space Complexity: O(log n)
@@ -860,21 +674,21 @@ export class BinaryTree<
860
674
  * identifier.
861
675
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
862
676
  * the binary tree. It is used to determine if a node matches the given identifier. The `callback`
863
- * function should take a single parameter of type `N` (the type of the nodes in the binary tree) and
864
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
677
+ * function should take a single parameter of type `NODE` (the type of the nodes in the binary tree) and
678
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
865
679
  * for searching the binary tree. It can be either a key value, a node object, or `null`/`undefined`.
866
680
  * If `null` or `undefined` is passed, the search will start from the root of the binary tree.
867
681
  * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
868
682
  * be performed when searching for nodes in the binary tree. It determines the order in which the
869
683
  * nodes are visited during the search.
870
- * @returns a value of type `N | null | undefined`.
684
+ * @returns a value of type `NODE | null | undefined`.
871
685
  */
872
- getNode<C extends BTNCallback<N>>(
686
+ getNode<C extends BTNCallback<NODE>>(
873
687
  identifier: ReturnType<C> | null | undefined,
874
688
  callback: C = this._defaultOneParamCallback as C,
875
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
689
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
876
690
  iterationType = this.iterationType
877
- ): N | null | undefined {
691
+ ): NODE | null | undefined {
878
692
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
879
693
  callback = (node => node) as C;
880
694
 
@@ -897,13 +711,13 @@ export class BinaryTree<
897
711
  * @param iterationType - The `iterationType` parameter is used to determine whether the search for
898
712
  * the node with the given key should be performed iteratively or recursively. It has two possible
899
713
  * values:
900
- * @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
714
+ * @returns The function `getNodeByKey` returns a node (`NODE`) if a node with the specified key is
901
715
  * found in the binary tree. If no node is found, it returns `undefined`.
902
716
  */
903
- getNodeByKey(key: K, iterationType = IterationType.ITERATIVE): N | undefined {
717
+ getNodeByKey(key: K, iterationType = IterationType.ITERATIVE): NODE | undefined {
904
718
  if (!this.root) return undefined;
905
719
  if (iterationType === IterationType.RECURSIVE) {
906
- const _dfs = (cur: N): N | undefined => {
720
+ const _dfs = (cur: NODE): NODE | undefined => {
907
721
  if (cur.key === key) return cur;
908
722
 
909
723
  if (!cur.left && !cur.right) return;
@@ -913,7 +727,7 @@ export class BinaryTree<
913
727
 
914
728
  return _dfs(this.root);
915
729
  } else {
916
- const queue = new Queue<N>([this.root]);
730
+ const queue = new Queue<NODE>([this.root]);
917
731
  while (queue.size > 0) {
918
732
  const cur = queue.shift();
919
733
  if (cur) {
@@ -925,27 +739,32 @@ export class BinaryTree<
925
739
  }
926
740
  }
927
741
 
928
- get<C extends BTNCallback<N, K>>(
742
+ override get<C extends BTNCallback<NODE, K>>(
929
743
  identifier: K,
930
744
  callback?: C,
931
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
745
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
932
746
  iterationType?: IterationType
933
747
  ): V | undefined;
934
748
 
935
- get<C extends BTNCallback<N, N>>(
936
- identifier: N | null | undefined,
749
+ override get<C extends BTNCallback<NODE, NODE>>(
750
+ identifier: NODE | null | undefined,
937
751
  callback?: C,
938
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
752
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
939
753
  iterationType?: IterationType
940
754
  ): V | undefined;
941
755
 
942
- get<C extends BTNCallback<N>>(
756
+ override get<C extends BTNCallback<NODE>>(
943
757
  identifier: ReturnType<C>,
944
758
  callback: C,
945
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
759
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
946
760
  iterationType?: IterationType
947
761
  ): V | undefined;
948
762
 
763
+ /**
764
+ * Time Complexity: O(n)
765
+ * Space Complexity: O(log n)
766
+ */
767
+
949
768
  /**
950
769
  * Time Complexity: O(n)
951
770
  * Space Complexity: O(log n)
@@ -959,19 +778,19 @@ export class BinaryTree<
959
778
  * the binary tree. It is used to determine whether a node matches the given identifier. The callback
960
779
  * function should return a value that can be compared to the identifier to determine if it is a
961
780
  * match.
962
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
781
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
963
782
  * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a
964
- * node), a node object of type `N`, or `null`/`undefined` to start the search from the root of
783
+ * node), a node object of type `NODE`, or `null`/`undefined` to start the search from the root of
965
784
  * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
966
785
  * be performed when searching for a node in the binary tree. It is an optional parameter with a
967
786
  * default value specified by `this.iterationType`.
968
787
  * @returns The value of the node with the given identifier is being returned. If the node is not
969
788
  * found, `undefined` is returned.
970
789
  */
971
- get<C extends BTNCallback<N>>(
790
+ override get<C extends BTNCallback<NODE>>(
972
791
  identifier: ReturnType<C> | null | undefined,
973
792
  callback: C = this._defaultOneParamCallback as C,
974
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
793
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
975
794
  iterationType = this.iterationType
976
795
  ): V | undefined {
977
796
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
@@ -980,55 +799,339 @@ export class BinaryTree<
980
799
  return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
981
800
  }
982
801
 
802
+ override has<C extends BTNCallback<NODE, K>>(
803
+ identifier: K,
804
+ callback?: C,
805
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
806
+ iterationType?: IterationType
807
+ ): boolean;
808
+
809
+ override has<C extends BTNCallback<NODE, NODE>>(
810
+ identifier: NODE | null | undefined,
811
+ callback?: C,
812
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
813
+ iterationType?: IterationType
814
+ ): boolean;
815
+
816
+ override has<C extends BTNCallback<NODE>>(
817
+ identifier: ReturnType<C> | null | undefined,
818
+ callback: C,
819
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
820
+ iterationType?: IterationType
821
+ ): boolean;
822
+
823
+ /**
824
+ * Time Complexity: O(n)
825
+ * Space Complexity: O(log n).
826
+ */
827
+
828
+ /**
829
+ * Time Complexity: O(n)
830
+ * Space Complexity: O(log n).
831
+ *
832
+ * The function checks if a Binary Tree Node with a specific identifier exists in the tree.
833
+ * @param {ReturnType<C> | null | undefined} identifier - The `identifier` parameter is the value
834
+ * that you want to search for in the binary tree. It can be of any type that is returned by the
835
+ * callback function `C`. It can also be `null` or `undefined` if you don't want to specify a
836
+ * specific identifier.
837
+ * @param {C} callback - The `callback` parameter is a function that will be called for each node in
838
+ * the binary tree. It is used to filter the nodes based on certain conditions. The `callback`
839
+ * function should return a boolean value indicating whether the node should be included in the
840
+ * result or not.
841
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
842
+ * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a
843
+ * node in the binary tree), a node object (`NODE`), or `null`/`undefined` to start the search from
844
+ * @param iterationType - The `iterationType` parameter is a variable that determines the type of
845
+ * iteration to be performed on the binary tree. It is used to specify whether the iteration should
846
+ * be performed in a pre-order, in-order, or post-order manner.
847
+ * @returns a boolean value.
848
+ */
849
+ override has<C extends BTNCallback<NODE>>(
850
+ identifier: ReturnType<C> | null | undefined,
851
+ callback: C = this._defaultOneParamCallback as C,
852
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
853
+ iterationType = this.iterationType
854
+ ): boolean {
855
+ if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
856
+ callback = (node => node) as C;
857
+
858
+ return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
859
+ }
860
+
861
+ /**
862
+ * Time Complexity: O(1)
863
+ * Space Complexity: O(1)
864
+ */
865
+
866
+ /**
867
+ * Time Complexity: O(1)
868
+ * Space Complexity: O(1)
869
+ *
870
+ * Clear the binary tree, removing all nodes.
871
+ */
872
+ clear() {
873
+ this._setRoot(undefined);
874
+ this._size = 0;
875
+ }
876
+
877
+ /**
878
+ * Time Complexity: O(1)
879
+ * Space Complexity: O(1)
880
+ */
881
+
882
+ /**
883
+ * Time Complexity: O(1)
884
+ * Space Complexity: O(1)
885
+ *
886
+ * Check if the binary tree is empty.
887
+ * @returns {boolean} - True if the binary tree is empty, false otherwise.
888
+ */
889
+ isEmpty(): boolean {
890
+ return this.size === 0;
891
+ }
892
+
893
+ /**
894
+ * Time Complexity: O(n)
895
+ * Space Complexity: O(log n)
896
+ */
897
+
898
+ /**
899
+ * Time Complexity: O(n)
900
+ * Space Complexity: O(log n)
901
+ *
902
+ * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the
903
+ * height of the tree.
904
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
905
+ * for calculating the height and minimum height of a binary tree. It can be either a `K` (a key
906
+ * value of a binary tree node), `NODE` (a node of a binary tree), `null`, or `undefined`. If
907
+ * @returns a boolean value.
908
+ */
909
+ isPerfectlyBalanced(beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root): boolean {
910
+ return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
911
+ }
912
+
913
+ /**
914
+ * Time Complexity: O(n)
915
+ * Space Complexity: O(1)
916
+ */
917
+
918
+ /**
919
+ * Time Complexity: O(n)
920
+ * Space Complexity: O(1)
921
+ *
922
+ * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree.
923
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the root
924
+ * node of the binary search tree (BST) that you want to check if it is a subtree of another BST.
925
+ * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
926
+ * type of iteration to use when checking if a subtree is a binary search tree (BST). It can have two
927
+ * possible values:
928
+ * @returns a boolean value.
929
+ */
930
+ isBST(beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root, iterationType = this.iterationType): boolean {
931
+ // TODO there is a bug
932
+ beginRoot = this.ensureNode(beginRoot);
933
+ if (!beginRoot) return true;
934
+
935
+ if (iterationType === IterationType.RECURSIVE) {
936
+ const dfs = (cur: NODE | null | undefined, min: number, max: number): boolean => {
937
+ if (!cur) return true;
938
+ const numKey = this.extractor(cur.key);
939
+ if (numKey <= min || numKey >= max) return false;
940
+ return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
941
+ };
942
+
943
+ const isStandardBST = dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
944
+ const isInverseBST = dfs(beginRoot, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
945
+ return isStandardBST || isInverseBST;
946
+ } else {
947
+ const checkBST = (checkMax = false) => {
948
+ const stack = [];
949
+ let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
950
+ // @ts-ignore
951
+ let curr: NODE | null | undefined = beginRoot;
952
+ while (curr || stack.length > 0) {
953
+ while (curr) {
954
+ stack.push(curr);
955
+ curr = curr.left;
956
+ }
957
+ curr = stack.pop()!;
958
+ const numKey = this.extractor(curr.key);
959
+ if (!curr || (!checkMax && prev >= numKey) || (checkMax && prev <= numKey)) return false;
960
+ prev = numKey;
961
+ curr = curr.right;
962
+ }
963
+ return true;
964
+ };
965
+ const isStandardBST = checkBST(false),
966
+ isInverseBST = checkBST(true);
967
+ return isStandardBST || isInverseBST;
968
+ }
969
+ }
970
+
971
+ /**
972
+ * Time Complexity: O(n)
973
+ * Space Complexity: O(1)
974
+ */
975
+
976
+ /**
977
+ * Time Complexity: O(n)
978
+ * Space Complexity: O(1)
979
+ *
980
+ * The function calculates the depth of a given node in a binary tree.
981
+ * @param {K | NODE | null | undefined} dist - The `dist` parameter represents the node in
982
+ * the binary tree whose depth we want to find. It can be of type `K`, `NODE`, `null`, or
983
+ * `undefined`.
984
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
985
+ * from which we want to calculate the depth. It can be either a `K` (binary tree node key) or
986
+ * `NODE` (binary tree node) or `null` or `undefined`. If no value is provided for `beginRoot
987
+ * @returns the depth of the `dist` relative to the `beginRoot`.
988
+ */
989
+ getDepth(dist: KeyOrNodeOrEntry<K, V, NODE>, beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root): number {
990
+ dist = this.ensureNode(dist);
991
+ beginRoot = this.ensureNode(beginRoot);
992
+ let depth = 0;
993
+ while (dist?.parent) {
994
+ if (dist === beginRoot) {
995
+ return depth;
996
+ }
997
+ depth++;
998
+ dist = dist.parent;
999
+ }
1000
+ return depth;
1001
+ }
1002
+
983
1003
  /**
984
- * Time Complexity: O(1)
1004
+ * Time Complexity: O(n)
985
1005
  * Space Complexity: O(1)
986
1006
  */
987
1007
 
988
1008
  /**
989
- * Time Complexity: O(1)
990
- * Space Complexity: O(1)
1009
+ * Time Complexity: O(n)
1010
+ * Space Complexity: O(log n)
991
1011
  *
992
- * Clear the binary tree, removing all nodes.
1012
+ * The function `getHeight` calculates the maximum height of a binary tree using either recursive or
1013
+ * iterative traversal.
1014
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
1015
+ * starting node of the binary tree from which we want to calculate the height. It can be of type
1016
+ * `K`, `NODE`, `null`, or `undefined`. If not provided, it defaults to `this.root`.
1017
+ * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the
1018
+ * height of the tree using a recursive approach or an iterative approach. It can have two possible
1019
+ * values:
1020
+ * @returns the height of the binary tree.
993
1021
  */
994
- clear() {
995
- this._setRoot(undefined);
996
- this._size = 0;
1022
+ getHeight(beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root, iterationType = this.iterationType): number {
1023
+ beginRoot = this.ensureNode(beginRoot);
1024
+ if (!beginRoot) return -1;
1025
+
1026
+ if (iterationType === IterationType.RECURSIVE) {
1027
+ const _getMaxHeight = (cur: NODE | null | undefined): number => {
1028
+ if (!cur) return -1;
1029
+ const leftHeight = _getMaxHeight(cur.left);
1030
+ const rightHeight = _getMaxHeight(cur.right);
1031
+ return Math.max(leftHeight, rightHeight) + 1;
1032
+ };
1033
+
1034
+ return _getMaxHeight(beginRoot);
1035
+ } else {
1036
+ const stack: { node: NODE; depth: number }[] = [{ node: beginRoot, depth: 0 }];
1037
+ let maxHeight = 0;
1038
+
1039
+ while (stack.length > 0) {
1040
+ const { node, depth } = stack.pop()!;
1041
+
1042
+ if (node.left) stack.push({ node: node.left, depth: depth + 1 });
1043
+ if (node.right) stack.push({ node: node.right, depth: depth + 1 });
1044
+
1045
+ maxHeight = Math.max(maxHeight, depth);
1046
+ }
1047
+
1048
+ return maxHeight;
1049
+ }
997
1050
  }
998
1051
 
999
1052
  /**
1000
- * Time Complexity: O(1)
1001
- * Space Complexity: O(1)
1053
+ * Time Complexity: O(n)
1054
+ * Space Complexity: O(log n)
1002
1055
  */
1003
1056
 
1004
1057
  /**
1005
- * Time Complexity: O(1)
1006
- * Space Complexity: O(1)
1058
+ * Time Complexity: O(n)
1059
+ * Space Complexity: O(log n)
1007
1060
  *
1008
- * Check if the binary tree is empty.
1009
- * @returns {boolean} - True if the binary tree is empty, false otherwise.
1061
+ * The `getMinHeight` function calculates the minimum height of a binary tree using either a
1062
+ * recursive or iterative approach.
1063
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
1064
+ * starting node of the binary tree from which we want to calculate the minimum height. It can be of
1065
+ * type `K`, `NODE`, `null`, or `undefined`. If no value is provided, it defaults to `this.root`.
1066
+ * @param iterationType - The `iterationType` parameter is used to determine the method of iteration
1067
+ * to calculate the minimum height of a binary tree. It can have two possible values:
1068
+ * @returns The function `getMinHeight` returns the minimum height of a binary tree.
1010
1069
  */
1011
- isEmpty(): boolean {
1012
- return this.size === 0;
1070
+ getMinHeight(beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root, iterationType = this.iterationType): number {
1071
+ beginRoot = this.ensureNode(beginRoot);
1072
+ if (!beginRoot) return -1;
1073
+
1074
+ if (iterationType === IterationType.RECURSIVE) {
1075
+ const _getMinHeight = (cur: NODE | null | undefined): number => {
1076
+ if (!cur) return 0;
1077
+ if (!cur.left && !cur.right) return 0;
1078
+ const leftMinHeight = _getMinHeight(cur.left);
1079
+ const rightMinHeight = _getMinHeight(cur.right);
1080
+ return Math.min(leftMinHeight, rightMinHeight) + 1;
1081
+ };
1082
+
1083
+ return _getMinHeight(beginRoot);
1084
+ } else {
1085
+ const stack: NODE[] = [];
1086
+ let node: NODE | null | undefined = beginRoot,
1087
+ last: NODE | null | undefined = null;
1088
+ const depths: Map<NODE, number> = new Map();
1089
+
1090
+ while (stack.length > 0 || node) {
1091
+ if (node) {
1092
+ stack.push(node);
1093
+ node = node.left;
1094
+ } else {
1095
+ node = stack[stack.length - 1];
1096
+ if (!node.right || last === node.right) {
1097
+ node = stack.pop();
1098
+ if (node) {
1099
+ const leftMinHeight = node.left ? depths.get(node.left) ?? -1 : -1;
1100
+ const rightMinHeight = node.right ? depths.get(node.right) ?? -1 : -1;
1101
+ depths.set(node, 1 + Math.min(leftMinHeight, rightMinHeight));
1102
+ last = node;
1103
+ node = null;
1104
+ }
1105
+ } else node = node.right;
1106
+ }
1107
+ }
1108
+
1109
+ return depths.get(beginRoot) ?? -1;
1110
+ }
1013
1111
  }
1014
1112
 
1015
1113
  /**
1114
+ * Time Complexity: O(log n)
1115
+ * Space Complexity: O(log n)
1116
+ * /
1117
+
1118
+ /**
1016
1119
  * Time Complexity: O(log n)
1017
1120
  * Space Complexity: O(log n)
1018
1121
  *
1019
1122
  * The function `getPathToRoot` returns an array of nodes from a given node to the root of a tree
1020
1123
  * structure, with the option to reverse the order of the nodes.
1021
- * @param {K | N | null | undefined} beginNode - The `beginRoot` parameter represents the
1022
- * starting node from which you want to find the path to the root. It can be of type `K`, `N`,
1124
+ * @param {K | NODE | null | undefined} beginNode - The `beginRoot` parameter represents the
1125
+ * starting node from which you want to find the path to the root. It can be of type `K`, `NODE`,
1023
1126
  * `null`, or `undefined`.
1024
1127
  * @param [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the
1025
1128
  * resulting path should be reversed or not. If `isReverse` is set to `true`, the path will be
1026
1129
  * reversed before returning it. If `isReverse` is set to `false`, the path will be returned as is
1027
- * @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
1130
+ * @returns The function `getPathToRoot` returns an array of nodes (`NODE[]`).
1028
1131
  */
1029
- getPathToRoot(beginNode: KeyOrNodeOrEntry<K, V, N>, isReverse = true): N[] {
1132
+ getPathToRoot(beginNode: KeyOrNodeOrEntry<K, V, NODE>, isReverse = true): NODE[] {
1030
1133
  // TODO to support get path through passing key
1031
- const result: N[] = [];
1134
+ const result: NODE[] = [];
1032
1135
  beginNode = this.ensureNode(beginNode);
1033
1136
 
1034
1137
  if (!beginNode) return result;
@@ -1054,24 +1157,24 @@ export class BinaryTree<
1054
1157
  *
1055
1158
  * The function `getLeftMost` returns the leftmost node in a binary tree, either recursively or
1056
1159
  * iteratively.
1057
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
1058
- * for finding the leftmost node in a binary tree. It can be either a `K` (a key value), `N` (a
1160
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
1161
+ * for finding the leftmost node in a binary tree. It can be either a `K` (a key value), `NODE` (a
1059
1162
  * node), `null`, or `undefined`. If not provided, it defaults to `this.root`,
1060
1163
  * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to
1061
1164
  * be performed when finding the leftmost node in a binary tree. It can have two possible values:
1062
- * @returns The function `getLeftMost` returns the leftmost node (`N`) in the binary tree. If there
1165
+ * @returns The function `getLeftMost` returns the leftmost node (`NODE`) in the binary tree. If there
1063
1166
  * is no leftmost node, it returns `null` or `undefined` depending on the input.
1064
1167
  */
1065
1168
  getLeftMost(
1066
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1169
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
1067
1170
  iterationType = this.iterationType
1068
- ): N | null | undefined {
1171
+ ): NODE | null | undefined {
1069
1172
  beginRoot = this.ensureNode(beginRoot);
1070
1173
 
1071
1174
  if (!beginRoot) return beginRoot;
1072
1175
 
1073
1176
  if (iterationType === IterationType.RECURSIVE) {
1074
- const _traverse = (cur: N): N => {
1177
+ const _traverse = (cur: NODE): NODE => {
1075
1178
  if (!this.isRealNode(cur.left)) return cur;
1076
1179
  return _traverse(cur.left);
1077
1180
  };
@@ -1079,7 +1182,7 @@ export class BinaryTree<
1079
1182
  return _traverse(beginRoot);
1080
1183
  } else {
1081
1184
  // Indirect implementation of iteration using tail recursion optimization
1082
- const _traverse = trampoline((cur: N) => {
1185
+ const _traverse = trampoline((cur: NODE) => {
1083
1186
  if (!this.isRealNode(cur.left)) return cur;
1084
1187
  return _traverse.cont(cur.left);
1085
1188
  });
@@ -1099,25 +1202,25 @@ export class BinaryTree<
1099
1202
  *
1100
1203
  * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or
1101
1204
  * iteratively.
1102
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1103
- * starting node from which we want to find the rightmost node. It can be of type `K`, `N`,
1205
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
1206
+ * starting node from which we want to find the rightmost node. It can be of type `K`, `NODE`,
1104
1207
  * `null`, or `undefined`. If not provided, it defaults to `this.root`, which is a property of the
1105
1208
  * current object.
1106
1209
  * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
1107
1210
  * type of iteration to use when finding the rightmost node. It can have one of two values:
1108
- * @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If there
1211
+ * @returns The function `getRightMost` returns the rightmost node (`NODE`) in a binary tree. If there
1109
1212
  * is no rightmost node, it returns `null` or `undefined`, depending on the input.
1110
1213
  */
1111
1214
  getRightMost(
1112
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1215
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
1113
1216
  iterationType = this.iterationType
1114
- ): N | null | undefined {
1217
+ ): NODE | null | undefined {
1115
1218
  // TODO support get right most by passing key in
1116
1219
  beginRoot = this.ensureNode(beginRoot);
1117
1220
  if (!beginRoot) return beginRoot;
1118
1221
 
1119
1222
  if (iterationType === IterationType.RECURSIVE) {
1120
- const _traverse = (cur: N): N => {
1223
+ const _traverse = (cur: NODE): NODE => {
1121
1224
  if (!this.isRealNode(cur.right)) return cur;
1122
1225
  return _traverse(cur.right);
1123
1226
  };
@@ -1125,7 +1228,7 @@ export class BinaryTree<
1125
1228
  return _traverse(beginRoot);
1126
1229
  } else {
1127
1230
  // Indirect implementation of iteration using tail recursion optimization
1128
- const _traverse = trampoline((cur: N) => {
1231
+ const _traverse = trampoline((cur: NODE) => {
1129
1232
  if (!this.isRealNode(cur.right)) return cur;
1130
1233
  return _traverse.cont(cur.right);
1131
1234
  });
@@ -1140,164 +1243,80 @@ export class BinaryTree<
1140
1243
  */
1141
1244
 
1142
1245
  /**
1143
- * Time Complexity: O(n)
1246
+ * Time Complexity: O(log n)
1144
1247
  * Space Complexity: O(1)
1145
1248
  *
1146
- * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree.
1147
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the root
1148
- * node of the binary search tree (BST) that you want to check if it is a subtree of another BST.
1149
- * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
1150
- * type of iteration to use when checking if a subtree is a binary search tree (BST). It can have two
1151
- * possible values:
1152
- * @returns a boolean value.
1249
+ * The function returns the predecessor of a given node in a tree.
1250
+ * @param {NODE} node - The parameter `node` is of type `RedBlackTreeNode`, which represents a node in a
1251
+ * tree.
1252
+ * @returns the predecessor of the given 'node'.
1153
1253
  */
1154
- isBST(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root, iterationType = this.iterationType): boolean {
1155
- // TODO there is a bug
1156
- beginRoot = this.ensureNode(beginRoot);
1157
- if (!beginRoot) return true;
1254
+ getPredecessor(node: NODE): NODE {
1255
+ if (this.isRealNode(node.left)) {
1256
+ let predecessor: NODE | null | undefined = node.left;
1257
+ while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
1258
+ if (this.isRealNode(predecessor)) {
1259
+ predecessor = predecessor.right;
1260
+ }
1261
+ }
1262
+ return predecessor;
1263
+ } else {
1264
+ return node;
1265
+ }
1266
+ }
1158
1267
 
1159
- if (iterationType === IterationType.RECURSIVE) {
1160
- const dfs = (cur: N | null | undefined, min: number, max: number): boolean => {
1161
- if (!cur) return true;
1162
- const numKey = this.extractor(cur.key);
1163
- if (numKey <= min || numKey >= max) return false;
1164
- return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
1165
- };
1268
+ /**
1269
+ * Time Complexity: O(log n)
1270
+ * Space Complexity: O(1)
1271
+ */
1166
1272
 
1167
- const isStandardBST = dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
1168
- const isInverseBST = dfs(beginRoot, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
1169
- return isStandardBST || isInverseBST;
1170
- } else {
1171
- const checkBST = (checkMax = false) => {
1172
- const stack = [];
1173
- let prev = checkMax ? Number.MAX_SAFE_INTEGER : Number.MIN_SAFE_INTEGER;
1174
- // @ts-ignore
1175
- let curr: N | null | undefined = beginRoot;
1176
- while (curr || stack.length > 0) {
1177
- while (curr) {
1178
- stack.push(curr);
1179
- curr = curr.left;
1180
- }
1181
- curr = stack.pop()!;
1182
- const numKey = this.extractor(curr.key);
1183
- if (!curr || (!checkMax && prev >= numKey) || (checkMax && prev <= numKey)) return false;
1184
- prev = numKey;
1185
- curr = curr.right;
1186
- }
1187
- return true;
1188
- };
1189
- const isStandardBST = checkBST(false),
1190
- isInverseBST = checkBST(true);
1191
- return isStandardBST || isInverseBST;
1273
+ /**
1274
+ * Time Complexity: O(log n)
1275
+ * Space Complexity: O(1)
1276
+ *
1277
+ * The function `getSuccessor` returns the next node in a binary tree given a current node.
1278
+ * @param {K | NODE | null} [x] - The parameter `x` can be of type `K`, `NODE`, or `null`.
1279
+ * @returns the successor of the given node or key. The successor is the node that comes immediately
1280
+ * after the given node in the inorder traversal of the binary tree.
1281
+ */
1282
+ getSuccessor(x?: K | NODE | null): NODE | null | undefined {
1283
+ x = this.ensureNode(x);
1284
+ if (!this.isRealNode(x)) return undefined;
1285
+
1286
+ if (this.isRealNode(x.right)) {
1287
+ return this.getLeftMost(x.right);
1288
+ }
1289
+
1290
+ let y: NODE | null | undefined = x.parent;
1291
+ while (this.isRealNode(y) && x === y.right) {
1292
+ x = y;
1293
+ y = y.parent;
1192
1294
  }
1295
+ return y;
1193
1296
  }
1194
1297
 
1195
- // /**
1196
- // * Time complexity: O(n)
1197
- // * Space complexity: O(log n)
1198
- // */
1199
- //
1200
- // subTreeTraverse<C extends BTNCallback<N>>(
1201
- // callback?: C,
1202
- // beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1203
- // iterationType?: IterationType,
1204
- // includeNull?: false
1205
- // ): ReturnType<C>[];
1206
- //
1207
- // subTreeTraverse<C extends BTNCallback<N | null>>(
1208
- // callback?: C,
1209
- // beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1210
- // iterationType?: IterationType,
1211
- // includeNull?: true
1212
- // ): ReturnType<C>[];
1213
- //
1214
- // /**
1215
- // * Time complexity: O(n)
1216
- // * Space complexity: O(log n)
1217
- // *
1218
- // * The function `subTreeTraverse` traverses a binary tree and applies a callback function to each
1219
- // * node, either recursively or iteratively.
1220
- // * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1221
- // * the subtree traversal. It takes a single parameter, which is the current node being traversed, and
1222
- // * returns a value of any type.
1223
- // * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1224
- // * starting node or key from which the subtree traversal should begin. It can be of type `K`,
1225
- // * `N`, `null`, or `undefined`. If not provided, the `root` property of the current object is used as
1226
- // * the default value.
1227
- // * @param iterationType - The `iterationType` parameter determines the type of traversal to be
1228
- // * performed on the subtree. It can have two possible values:
1229
- // * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
1230
- // * whether to include null values in the traversal. If `includeNull` is set to `true`, the
1231
- // * traversal will include null values, otherwise it will skip them.
1232
- // * @returns The function `subTreeTraverse` returns an array of values that are the result of invoking
1233
- // * the `callback` function on each node in the subtree. The type of the array nodes is determined
1234
- // * by the return type of the `callback` function.
1235
- // */
1236
- // subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
1237
- // callback: C = this._defaultOneParamCallback as C,
1238
- // beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1239
- // iterationType = this.iterationType,
1240
- // includeNull = false
1241
- // ): ReturnType<C>[] {
1242
- // console.warn('subTreeTraverse is unnecessary, since the dfs method can substitute it.');
1243
- //
1244
- // beginRoot = this.ensureNode(beginRoot);
1245
- //
1246
- // const ans: (ReturnType<BTNCallback<N>> | null | undefined)[] = [];
1247
- // if (!beginRoot) return ans;
1248
- //
1249
- // if (iterationType === IterationType.RECURSIVE) {
1250
- // const _traverse = (cur: N | null | undefined) => {
1251
- // if (cur !== undefined) {
1252
- // ans.push(callback(cur));
1253
- // if (includeNull) {
1254
- // cur && this.isNodeOrNull(cur.left) && _traverse(cur.left);
1255
- // cur && this.isNodeOrNull(cur.right) && _traverse(cur.right);
1256
- // } else {
1257
- // cur && cur.left && _traverse(cur.left);
1258
- // cur && cur.right && _traverse(cur.right);
1259
- // }
1260
- // }
1261
- // };
1262
- //
1263
- // _traverse(beginRoot);
1264
- // } else {
1265
- // const stack: (N | null | undefined)[] = [beginRoot];
1266
- //
1267
- // while (stack.length > 0) {
1268
- // const cur = stack.pop();
1269
- // if (cur !== undefined) {
1270
- // ans.push(callback(cur));
1271
- // if (includeNull) {
1272
- // cur && this.isNodeOrNull(cur.right) && stack.push(cur.right);
1273
- // cur && this.isNodeOrNull(cur.left) && stack.push(cur.left);
1274
- // } else {
1275
- // cur && cur.right && stack.push(cur.right);
1276
- // cur && cur.left && stack.push(cur.left);
1277
- // }
1278
- // }
1279
- // }
1280
- // }
1281
- // return ans;
1282
- // }
1283
-
1284
- dfs<C extends BTNCallback<N>>(
1298
+ dfs<C extends BTNCallback<NODE>>(
1285
1299
  callback?: C,
1286
1300
  pattern?: DFSOrderPattern,
1287
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1301
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1288
1302
  iterationType?: IterationType,
1289
1303
  includeNull?: false
1290
1304
  ): ReturnType<C>[];
1291
1305
 
1292
- dfs<C extends BTNCallback<N | null>>(
1306
+ dfs<C extends BTNCallback<NODE | null>>(
1293
1307
  callback?: C,
1294
1308
  pattern?: DFSOrderPattern,
1295
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1309
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1296
1310
  iterationType?: IterationType,
1297
1311
  includeNull?: true
1298
1312
  ): ReturnType<C>[];
1299
1313
 
1300
1314
  /**
1315
+ * Time complexity: O(n)
1316
+ * Space complexity: O(n)
1317
+ * /
1318
+
1319
+ /**
1301
1320
  * Time complexity: O(n)
1302
1321
  * Space complexity: O(n)
1303
1322
  *
@@ -1305,11 +1324,11 @@ export class BinaryTree<
1305
1324
  * specified pattern and iteration type, and returns an array of values obtained from applying a
1306
1325
  * callback function to each visited node.
1307
1326
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1308
- * the tree during the depth-first search. It takes a single parameter, which can be of type `N`,
1327
+ * the tree during the depth-first search. It takes a single parameter, which can be of type `NODE`,
1309
1328
  * `null`, or `undefined`, and returns a value of any type. The default value for this parameter is
1310
1329
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
1311
1330
  * nodes are traversed during the depth-first search. It can have one of the following values:
1312
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1331
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1313
1332
  * for the depth-first search traversal. It can be specified as a key, a node object, or
1314
1333
  * `null`/`undefined`. If not provided, the `beginRoot` will default to the root node of the tree.
1315
1334
  * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
@@ -1320,10 +1339,10 @@ export class BinaryTree<
1320
1339
  * `false`, null or undefined
1321
1340
  * @returns an array of values that are the return values of the callback function.
1322
1341
  */
1323
- dfs<C extends BTNCallback<N | null | undefined>>(
1342
+ dfs<C extends BTNCallback<NODE | null | undefined>>(
1324
1343
  callback: C = this._defaultOneParamCallback as C,
1325
1344
  pattern: DFSOrderPattern = 'in',
1326
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1345
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
1327
1346
  iterationType: IterationType = IterationType.ITERATIVE,
1328
1347
  includeNull = false
1329
1348
  ): ReturnType<C>[] {
@@ -1331,7 +1350,7 @@ export class BinaryTree<
1331
1350
  if (!beginRoot) return [];
1332
1351
  const ans: ReturnType<C>[] = [];
1333
1352
  if (iterationType === IterationType.RECURSIVE) {
1334
- const _traverse = (node: N | null | undefined) => {
1353
+ const _traverse = (node: NODE | null | undefined) => {
1335
1354
  switch (pattern) {
1336
1355
  case 'in':
1337
1356
  if (includeNull) {
@@ -1373,7 +1392,7 @@ export class BinaryTree<
1373
1392
  _traverse(beginRoot);
1374
1393
  } else {
1375
1394
  // 0: visit, 1: print
1376
- const stack: { opt: 0 | 1; node: N | null | undefined }[] = [{ opt: 0, node: beginRoot }];
1395
+ const stack: { opt: 0 | 1; node: NODE | null | undefined }[] = [{ opt: 0, node: beginRoot }];
1377
1396
 
1378
1397
  while (stack.length > 0) {
1379
1398
  const cur = stack.pop();
@@ -1415,25 +1434,25 @@ export class BinaryTree<
1415
1434
  return ans;
1416
1435
  }
1417
1436
 
1418
- /**
1419
- * Time complexity: O(n)
1420
- * Space complexity: O(n)
1421
- */
1422
-
1423
- bfs<C extends BTNCallback<N>>(
1437
+ bfs<C extends BTNCallback<NODE>>(
1424
1438
  callback?: C,
1425
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1439
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1426
1440
  iterationType?: IterationType,
1427
1441
  includeNull?: false
1428
1442
  ): ReturnType<C>[];
1429
1443
 
1430
- bfs<C extends BTNCallback<N | null>>(
1444
+ bfs<C extends BTNCallback<NODE | null>>(
1431
1445
  callback?: C,
1432
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1446
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1433
1447
  iterationType?: IterationType,
1434
1448
  includeNull?: true
1435
1449
  ): ReturnType<C>[];
1436
1450
 
1451
+ /**
1452
+ * Time complexity: O(n)
1453
+ * Space complexity: O(n)
1454
+ */
1455
+
1437
1456
  /**
1438
1457
  * Time complexity: O(n)
1439
1458
  * Space complexity: O(n)
@@ -1443,7 +1462,7 @@ export class BinaryTree<
1443
1462
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1444
1463
  * the breadth-first search traversal. It takes a single parameter, which is the current node being
1445
1464
  * visited, and returns a value of any type.
1446
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1465
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
1447
1466
  * starting node for the breadth-first search traversal. It can be specified as a key, a node object,
1448
1467
  * or `null`/`undefined` to indicate the root of the tree. If not provided, the `root` property of
1449
1468
  * the class is used as
@@ -1455,19 +1474,19 @@ export class BinaryTree<
1455
1474
  * @returns an array of values that are the result of invoking the callback function on each node in
1456
1475
  * the breadth-first traversal of a binary tree.
1457
1476
  */
1458
- bfs<C extends BTNCallback<N | null>>(
1477
+ bfs<C extends BTNCallback<NODE | null>>(
1459
1478
  callback: C = this._defaultOneParamCallback as C,
1460
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1479
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
1461
1480
  iterationType = this.iterationType,
1462
1481
  includeNull = false
1463
1482
  ): ReturnType<C>[] {
1464
1483
  beginRoot = this.ensureNode(beginRoot);
1465
1484
  if (!beginRoot) return [];
1466
1485
 
1467
- const ans: ReturnType<BTNCallback<N>>[] = [];
1486
+ const ans: ReturnType<BTNCallback<NODE>>[] = [];
1468
1487
 
1469
1488
  if (iterationType === IterationType.RECURSIVE) {
1470
- const queue: Queue<N | null | undefined> = new Queue<N | null | undefined>([beginRoot]);
1489
+ const queue: Queue<NODE | null | undefined> = new Queue<NODE | null | undefined>([beginRoot]);
1471
1490
 
1472
1491
  const traverse = (level: number) => {
1473
1492
  if (queue.size === 0) return;
@@ -1488,7 +1507,7 @@ export class BinaryTree<
1488
1507
 
1489
1508
  traverse(0);
1490
1509
  } else {
1491
- const queue = new Queue<N | null | undefined>([beginRoot]);
1510
+ const queue = new Queue<NODE | null | undefined>([beginRoot]);
1492
1511
  while (queue.size > 0) {
1493
1512
  const levelSize = queue.size;
1494
1513
 
@@ -1509,25 +1528,25 @@ export class BinaryTree<
1509
1528
  return ans;
1510
1529
  }
1511
1530
 
1512
- /**
1513
- * Time complexity: O(n)
1514
- * Space complexity: O(n)
1515
- */
1516
-
1517
- listLevels<C extends BTNCallback<N>>(
1531
+ listLevels<C extends BTNCallback<NODE>>(
1518
1532
  callback?: C,
1519
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1533
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1520
1534
  iterationType?: IterationType,
1521
1535
  includeNull?: false
1522
1536
  ): ReturnType<C>[][];
1523
1537
 
1524
- listLevels<C extends BTNCallback<N | null>>(
1538
+ listLevels<C extends BTNCallback<NODE | null>>(
1525
1539
  callback?: C,
1526
- beginRoot?: KeyOrNodeOrEntry<K, V, N>,
1540
+ beginRoot?: KeyOrNodeOrEntry<K, V, NODE>,
1527
1541
  iterationType?: IterationType,
1528
1542
  includeNull?: true
1529
1543
  ): ReturnType<C>[][];
1530
1544
 
1545
+ /**
1546
+ * Time complexity: O(n)
1547
+ * Space complexity: O(n)
1548
+ */
1549
+
1531
1550
  /**
1532
1551
  * Time complexity: O(n)
1533
1552
  * Space complexity: O(n)
@@ -1536,10 +1555,10 @@ export class BinaryTree<
1536
1555
  * a binary tree and contains the values returned by a callback function applied to the nodes at that
1537
1556
  * level.
1538
1557
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1539
- * the tree. It takes a single parameter, which can be of type `N`, `null`, or `undefined`, and
1558
+ * the tree. It takes a single parameter, which can be of type `NODE`, `null`, or `undefined`, and
1540
1559
  * returns a value of any type.
1541
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1542
- * starting node for traversing the tree. It can be either a node object (`N`), a key value
1560
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter represents the
1561
+ * starting node for traversing the tree. It can be either a node object (`NODE`), a key value
1543
1562
  * (`K`), `null`, or `undefined`. If not provided, it defaults to the root node of the tree.
1544
1563
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be
1545
1564
  * performed on the tree. It can have two possible values:
@@ -1549,9 +1568,9 @@ export class BinaryTree<
1549
1568
  * be excluded
1550
1569
  * @returns The function `listLevels` returns a two-dimensional array of type `ReturnType<C>[][]`.
1551
1570
  */
1552
- listLevels<C extends BTNCallback<N | null>>(
1571
+ listLevels<C extends BTNCallback<NODE | null>>(
1553
1572
  callback: C = this._defaultOneParamCallback as C,
1554
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root,
1573
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root,
1555
1574
  iterationType = this.iterationType,
1556
1575
  includeNull = false
1557
1576
  ): ReturnType<C>[][] {
@@ -1560,7 +1579,7 @@ export class BinaryTree<
1560
1579
  if (!beginRoot) return levelsNodes;
1561
1580
 
1562
1581
  if (iterationType === IterationType.RECURSIVE) {
1563
- const _recursive = (node: N | null, level: number) => {
1582
+ const _recursive = (node: NODE | null, level: number) => {
1564
1583
  if (!levelsNodes[level]) levelsNodes[level] = [];
1565
1584
  levelsNodes[level].push(callback(node));
1566
1585
  if (includeNull) {
@@ -1574,7 +1593,7 @@ export class BinaryTree<
1574
1593
 
1575
1594
  _recursive(beginRoot, 0);
1576
1595
  } else {
1577
- const stack: [N | null, number][] = [[beginRoot, 0]];
1596
+ const stack: [NODE | null, number][] = [[beginRoot, 0]];
1578
1597
 
1579
1598
  while (stack.length > 0) {
1580
1599
  const head = stack.pop()!;
@@ -1596,56 +1615,6 @@ export class BinaryTree<
1596
1615
  return levelsNodes;
1597
1616
  }
1598
1617
 
1599
- /**
1600
- * Time Complexity: O(log n)
1601
- * Space Complexity: O(1)
1602
- */
1603
-
1604
- /**
1605
- * Time Complexity: O(log n)
1606
- * Space Complexity: O(1)
1607
- *
1608
- * The function returns the predecessor of a given node in a tree.
1609
- * @param {N} node - The parameter `node` is of type `RedBlackTreeNode`, which represents a node in a
1610
- * tree.
1611
- * @returns the predecessor of the given 'node'.
1612
- */
1613
- getPredecessor(node: N): N {
1614
- if (this.isRealNode(node.left)) {
1615
- let predecessor: N | null | undefined = node.left;
1616
- while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
1617
- if (this.isRealNode(predecessor)) {
1618
- predecessor = predecessor.right;
1619
- }
1620
- }
1621
- return predecessor;
1622
- } else {
1623
- return node;
1624
- }
1625
- }
1626
-
1627
- /**
1628
- * The function `getSuccessor` returns the next node in a binary tree given a current node.
1629
- * @param {K | N | null} [x] - The parameter `x` can be of type `K`, `N`, or `null`.
1630
- * @returns the successor of the given node or key. The successor is the node that comes immediately
1631
- * after the given node in the inorder traversal of the binary tree.
1632
- */
1633
- getSuccessor(x?: K | N | null): N | null | undefined {
1634
- x = this.ensureNode(x);
1635
- if (!this.isRealNode(x)) return undefined;
1636
-
1637
- if (this.isRealNode(x.right)) {
1638
- return this.getLeftMost(x.right);
1639
- }
1640
-
1641
- let y: N | null | undefined = x.parent;
1642
- while (this.isRealNode(y) && x === y.right) {
1643
- x = y;
1644
- y = y.parent;
1645
- }
1646
- return y;
1647
- }
1648
-
1649
1618
  /**
1650
1619
  * Time complexity: O(n)
1651
1620
  * Space complexity: O(n)
@@ -1658,31 +1627,31 @@ export class BinaryTree<
1658
1627
  * The `morris` function performs a depth-first traversal on a binary tree using the Morris traversal
1659
1628
  * algorithm.
1660
1629
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1661
- * the tree. It takes a single parameter of type `N` (the type of the nodes in the tree) and returns
1630
+ * the tree. It takes a single parameter of type `NODE` (the type of the nodes in the tree) and returns
1662
1631
  * a value of any type.
1663
1632
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
1664
1633
  * determines the order in which the nodes of a binary tree are traversed. It can have one of the
1665
1634
  * following values:
1666
- * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1635
+ * @param {K | NODE | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1667
1636
  * for the traversal. It can be specified as a key, a node object, or `null`/`undefined` to indicate
1668
1637
  * the root of the tree. If no value is provided, the default value is the root of the tree.
1669
1638
  * @returns The function `morris` returns an array of values that are the result of invoking the
1670
1639
  * `callback` function on each node in the binary tree. The type of the array nodes is determined
1671
1640
  * by the return type of the `callback` function.
1672
1641
  */
1673
- morris<C extends BTNCallback<N>>(
1642
+ morris<C extends BTNCallback<NODE>>(
1674
1643
  callback: C = this._defaultOneParamCallback as C,
1675
1644
  pattern: DFSOrderPattern = 'in',
1676
- beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root
1645
+ beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root
1677
1646
  ): ReturnType<C>[] {
1678
1647
  beginRoot = this.ensureNode(beginRoot);
1679
1648
  if (beginRoot === null) return [];
1680
- const ans: ReturnType<BTNCallback<N>>[] = [];
1649
+ const ans: ReturnType<BTNCallback<NODE>>[] = [];
1681
1650
 
1682
- let cur: N | null | undefined = beginRoot;
1683
- const _reverseEdge = (node: N | null | undefined) => {
1684
- let pre: N | null | undefined = null;
1685
- let next: N | null | undefined = null;
1651
+ let cur: NODE | null | undefined = beginRoot;
1652
+ const _reverseEdge = (node: NODE | null | undefined) => {
1653
+ let pre: NODE | null | undefined = null;
1654
+ let next: NODE | null | undefined = null;
1686
1655
  while (node) {
1687
1656
  next = node.right;
1688
1657
  node.right = pre;
@@ -1691,9 +1660,9 @@ export class BinaryTree<
1691
1660
  }
1692
1661
  return pre;
1693
1662
  };
1694
- const _printEdge = (node: N | null | undefined) => {
1695
- const tail: N | null | undefined = _reverseEdge(node);
1696
- let cur: N | null | undefined = tail;
1663
+ const _printEdge = (node: NODE | null | undefined) => {
1664
+ const tail: NODE | null | undefined = _reverseEdge(node);
1665
+ let cur: NODE | null | undefined = tail;
1697
1666
  while (cur) {
1698
1667
  ans.push(callback(cur));
1699
1668
  cur = cur.right;
@@ -1771,7 +1740,15 @@ export class BinaryTree<
1771
1740
  */
1772
1741
  clone(): TREE {
1773
1742
  const cloned = this.createTree();
1774
- this.bfs(node => cloned.add([node.key, node.value]));
1743
+ this.bfs(
1744
+ node => {
1745
+ if (node === null) cloned.add(null);
1746
+ else cloned.add([node.key, node.value]);
1747
+ },
1748
+ this.root,
1749
+ this.iterationType,
1750
+ true
1751
+ );
1775
1752
  return cloned;
1776
1753
  }
1777
1754
 
@@ -1855,12 +1832,12 @@ export class BinaryTree<
1855
1832
  * Space Complexity: O(n)
1856
1833
  *
1857
1834
  * The `print` function is used to display a binary tree structure in a visually appealing way.
1858
- * @param {K | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `K | N | null |
1835
+ * @param {K | NODE | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `K | NODE | null |
1859
1836
  * undefined`. It represents the root node of a binary tree. The root node can have one of the
1860
1837
  * following types:
1861
1838
  * @param {BinaryTreePrintOptions} [options={ isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false}] - Options object that controls printing behavior. You can specify whether to display undefined, null, or sentinel nodes.
1862
1839
  */
1863
- print(beginRoot: KeyOrNodeOrEntry<K, V, N> = this.root, options?: BinaryTreePrintOptions): void {
1840
+ print(beginRoot: KeyOrNodeOrEntry<K, V, NODE> = this.root, options?: BinaryTreePrintOptions): void {
1864
1841
  const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1865
1842
  beginRoot = this.ensureNode(beginRoot);
1866
1843
  if (!beginRoot) return;
@@ -1869,13 +1846,13 @@ export class BinaryTree<
1869
1846
  console.log(`U for undefined
1870
1847
  `);
1871
1848
  if (opts.isShowNull)
1872
- console.log(`N for null
1849
+ console.log(`NODE for null
1873
1850
  `);
1874
1851
  if (opts.isShowRedBlackNIL)
1875
1852
  console.log(`S for Sentinel Node
1876
1853
  `);
1877
1854
 
1878
- const display = (root: N | null | undefined): void => {
1855
+ const display = (root: NODE | null | undefined): void => {
1879
1856
  const [lines, , ,] = this._displayAux(root, opts);
1880
1857
  for (const line of lines) {
1881
1858
  console.log(line);
@@ -1885,12 +1862,21 @@ export class BinaryTree<
1885
1862
  display(beginRoot);
1886
1863
  }
1887
1864
 
1865
+ /**
1866
+ * The function `_getIterator` is a protected generator function that returns an iterator for the
1867
+ * key-value pairs in a binary search tree.
1868
+ * @param node - The `node` parameter represents the current node in the binary search tree. It is an
1869
+ * optional parameter with a default value of `this.root`, which means if no node is provided, the
1870
+ * root node of the tree will be used as the starting point for iteration.
1871
+ * @returns The function `_getIterator` returns an `IterableIterator` of key-value pairs `[K, V |
1872
+ * undefined]`.
1873
+ */
1888
1874
  protected* _getIterator(node = this.root): IterableIterator<[K, V | undefined]> {
1889
1875
  if (!node) return;
1890
1876
 
1891
1877
  if (this.iterationType === IterationType.ITERATIVE) {
1892
- const stack: (N | null | undefined)[] = [];
1893
- let current: N | null | undefined = node;
1878
+ const stack: (NODE | null | undefined)[] = [];
1879
+ let current: NODE | null | undefined = node;
1894
1880
 
1895
1881
  while (current || stack.length > 0) {
1896
1882
  while (current && !isNaN(this.extractor(current.key))) {
@@ -1916,7 +1902,21 @@ export class BinaryTree<
1916
1902
  }
1917
1903
  }
1918
1904
 
1919
- protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
1905
+ /**
1906
+ * The `_displayAux` function is responsible for generating the display layout of a binary tree node,
1907
+ * taking into account various options such as whether to show null, undefined, or NaN nodes.
1908
+ * @param {NODE | null | undefined} node - The `node` parameter represents a node in a binary tree.
1909
+ * It can be of type `NODE`, `null`, or `undefined`.
1910
+ * @param {BinaryTreePrintOptions} options - The `options` parameter is an object that contains the
1911
+ * following properties:
1912
+ * @returns The function `_displayAux` returns a `NodeDisplayLayout` which is an array containing the
1913
+ * following elements:
1914
+ * 1. `mergedLines`: An array of strings representing the lines of the node display.
1915
+ * 2. `totalWidth`: The total width of the node display.
1916
+ * 3. `totalHeight`: The total height of the node display.
1917
+ * 4. `middleIndex`: The index of the middle character
1918
+ */
1919
+ protected _displayAux(node: NODE | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
1920
1920
  const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
1921
1921
  const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
1922
1922
 
@@ -1942,7 +1942,7 @@ export class BinaryTree<
1942
1942
  );
1943
1943
  } else {
1944
1944
  // For cases where none of the conditions are met, null, undefined, and NaN nodes are not displayed
1945
- const line = node === undefined ? 'U' : 'N',
1945
+ const line = node === undefined ? 'U' : 'NODE',
1946
1946
  width = line.length;
1947
1947
 
1948
1948
  return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0]);
@@ -1984,15 +1984,18 @@ export class BinaryTree<
1984
1984
  }
1985
1985
  }
1986
1986
 
1987
- protected _defaultOneParamCallback = (node: N | null | undefined) => (node ? node.key : undefined);
1987
+ protected _defaultOneParamCallback = (node: NODE | null | undefined) => (node ? node.key : undefined);
1988
1988
 
1989
1989
  /**
1990
1990
  * Swap the data of two nodes in the binary tree.
1991
- * @param {N} srcNode - The source node to swap.
1992
- * @param {N} destNode - The destination node to swap.
1993
- * @returns {N} - The destination node after the swap.
1994
- */
1995
- protected _swapProperties(srcNode: KeyOrNodeOrEntry<K, V, N>, destNode: KeyOrNodeOrEntry<K, V, N>): N | undefined {
1991
+ * @param {NODE} srcNode - The source node to swap.
1992
+ * @param {NODE} destNode - The destination node to swap.
1993
+ * @returns {NODE} - The destination node after the swap.
1994
+ */
1995
+ protected _swapProperties(
1996
+ srcNode: KeyOrNodeOrEntry<K, V, NODE>,
1997
+ destNode: KeyOrNodeOrEntry<K, V, NODE>
1998
+ ): NODE | undefined {
1996
1999
  srcNode = this.ensureNode(srcNode);
1997
2000
  destNode = this.ensureNode(destNode);
1998
2001
 
@@ -2015,13 +2018,13 @@ export class BinaryTree<
2015
2018
 
2016
2019
  /**
2017
2020
  * The function replaces an old node with a new node in a binary tree.
2018
- * @param {N} oldNode - The oldNode parameter represents the node that needs to be replaced in the
2021
+ * @param {NODE} oldNode - The oldNode parameter represents the node that needs to be replaced in the
2019
2022
  * tree.
2020
- * @param {N} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the
2023
+ * @param {NODE} newNode - The `newNode` parameter is the node that will replace the `oldNode` in the
2021
2024
  * tree.
2022
2025
  * @returns The method is returning the newNode.
2023
2026
  */
2024
- protected _replaceNode(oldNode: N, newNode: N): N {
2027
+ protected _replaceNode(oldNode: NODE, newNode: NODE): NODE {
2025
2028
  if (oldNode.parent) {
2026
2029
  if (oldNode.parent.left === oldNode) {
2027
2030
  oldNode.parent.left = newNode;
@@ -2042,10 +2045,10 @@ export class BinaryTree<
2042
2045
  /**
2043
2046
  * The function sets the root property of an object to a given value, and if the value is not null,
2044
2047
  * it also sets the parent property of the value to undefined.
2045
- * @param {N | null | undefined} v - The parameter `v` is of type `N | null | undefined`, which means it can either be of
2046
- * type `N` or `null`.
2048
+ * @param {NODE | null | undefined} v - The parameter `v` is of type `NODE | null | undefined`, which means it can either be of
2049
+ * type `NODE` or `null`.
2047
2050
  */
2048
- protected _setRoot(v: N | null | undefined) {
2051
+ protected _setRoot(v: NODE | null | undefined) {
2049
2052
  if (v) {
2050
2053
  v.parent = undefined;
2051
2054
  }