directed-graph-typed 1.48.0 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/data-structures/base/index.d.ts +1 -0
  2. package/dist/data-structures/base/index.js +17 -0
  3. package/dist/data-structures/base/iterable-base.d.ts +232 -0
  4. package/dist/data-structures/base/iterable-base.js +312 -0
  5. package/dist/data-structures/binary-tree/avl-tree.d.ts +28 -19
  6. package/dist/data-structures/binary-tree/avl-tree.js +22 -11
  7. package/dist/data-structures/binary-tree/binary-tree.d.ts +158 -152
  8. package/dist/data-structures/binary-tree/binary-tree.js +241 -215
  9. package/dist/data-structures/binary-tree/bst.d.ts +64 -48
  10. package/dist/data-structures/binary-tree/bst.js +94 -65
  11. package/dist/data-structures/binary-tree/rb-tree.d.ts +39 -39
  12. package/dist/data-structures/binary-tree/rb-tree.js +42 -49
  13. package/dist/data-structures/binary-tree/tree-multimap.d.ts +60 -34
  14. package/dist/data-structures/binary-tree/tree-multimap.js +59 -27
  15. package/dist/data-structures/graph/abstract-graph.d.ts +92 -53
  16. package/dist/data-structures/graph/abstract-graph.js +130 -103
  17. package/dist/data-structures/graph/directed-graph.d.ts +70 -52
  18. package/dist/data-structures/graph/directed-graph.js +111 -65
  19. package/dist/data-structures/graph/map-graph.d.ts +5 -5
  20. package/dist/data-structures/graph/map-graph.js +8 -8
  21. package/dist/data-structures/graph/undirected-graph.d.ts +51 -32
  22. package/dist/data-structures/graph/undirected-graph.js +117 -54
  23. package/dist/data-structures/hash/hash-map.d.ts +160 -44
  24. package/dist/data-structures/hash/hash-map.js +314 -82
  25. package/dist/data-structures/heap/heap.d.ts +50 -7
  26. package/dist/data-structures/heap/heap.js +60 -30
  27. package/dist/data-structures/index.d.ts +1 -0
  28. package/dist/data-structures/index.js +1 -0
  29. package/dist/data-structures/linked-list/doubly-linked-list.d.ts +42 -55
  30. package/dist/data-structures/linked-list/doubly-linked-list.js +50 -77
  31. package/dist/data-structures/linked-list/singly-linked-list.d.ts +36 -55
  32. package/dist/data-structures/linked-list/singly-linked-list.js +44 -77
  33. package/dist/data-structures/queue/deque.d.ts +35 -167
  34. package/dist/data-structures/queue/deque.js +43 -249
  35. package/dist/data-structures/queue/queue.d.ts +49 -48
  36. package/dist/data-structures/queue/queue.js +69 -82
  37. package/dist/data-structures/stack/stack.d.ts +43 -10
  38. package/dist/data-structures/stack/stack.js +50 -31
  39. package/dist/data-structures/trie/trie.d.ts +41 -6
  40. package/dist/data-structures/trie/trie.js +53 -32
  41. package/dist/interfaces/binary-tree.d.ts +6 -6
  42. package/dist/types/common.d.ts +11 -8
  43. package/dist/types/common.js +6 -1
  44. package/dist/types/data-structures/base/base.d.ts +5 -0
  45. package/dist/types/data-structures/base/base.js +2 -0
  46. package/dist/types/data-structures/base/index.d.ts +1 -0
  47. package/dist/types/data-structures/base/index.js +17 -0
  48. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +3 -3
  49. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +4 -4
  50. package/dist/types/data-structures/binary-tree/bst.d.ts +6 -6
  51. package/dist/types/data-structures/binary-tree/rb-tree.d.ts +3 -3
  52. package/dist/types/data-structures/binary-tree/tree-multimap.d.ts +3 -3
  53. package/dist/types/data-structures/hash/hash-map.d.ts +4 -0
  54. package/dist/types/data-structures/index.d.ts +1 -0
  55. package/dist/types/data-structures/index.js +1 -0
  56. package/package.json +2 -2
  57. package/src/data-structures/base/index.ts +1 -0
  58. package/src/data-structures/base/iterable-base.ts +329 -0
  59. package/src/data-structures/binary-tree/avl-tree.ts +37 -25
  60. package/src/data-structures/binary-tree/binary-tree.ts +336 -296
  61. package/src/data-structures/binary-tree/bst.ts +135 -89
  62. package/src/data-structures/binary-tree/rb-tree.ts +60 -69
  63. package/src/data-structures/binary-tree/tree-multimap.ts +86 -49
  64. package/src/data-structures/graph/abstract-graph.ts +136 -104
  65. package/src/data-structures/graph/directed-graph.ts +114 -65
  66. package/src/data-structures/graph/map-graph.ts +8 -8
  67. package/src/data-structures/graph/undirected-graph.ts +124 -56
  68. package/src/data-structures/hash/hash-map.ts +335 -84
  69. package/src/data-structures/heap/heap.ts +63 -36
  70. package/src/data-structures/index.ts +1 -0
  71. package/src/data-structures/linked-list/doubly-linked-list.ts +54 -83
  72. package/src/data-structures/linked-list/singly-linked-list.ts +49 -84
  73. package/src/data-structures/queue/deque.ts +43 -275
  74. package/src/data-structures/queue/queue.ts +71 -86
  75. package/src/data-structures/stack/stack.ts +53 -34
  76. package/src/data-structures/trie/trie.ts +58 -35
  77. package/src/interfaces/binary-tree.ts +5 -6
  78. package/src/types/common.ts +11 -8
  79. package/src/types/data-structures/base/base.ts +6 -0
  80. package/src/types/data-structures/base/index.ts +1 -0
  81. package/src/types/data-structures/binary-tree/avl-tree.ts +3 -3
  82. package/src/types/data-structures/binary-tree/binary-tree.ts +6 -5
  83. package/src/types/data-structures/binary-tree/bst.ts +6 -6
  84. package/src/types/data-structures/binary-tree/rb-tree.ts +3 -3
  85. package/src/types/data-structures/binary-tree/tree-multimap.ts +3 -3
  86. package/src/types/data-structures/hash/hash-map.ts +2 -0
  87. package/src/types/data-structures/heap/heap.ts +1 -1
  88. package/src/types/data-structures/index.ts +1 -0
  89. package/src/types/data-structures/priority-queue/priority-queue.ts +1 -1
@@ -10,16 +10,16 @@ import type {
10
10
  BinaryTreeNodeNested,
11
11
  BinaryTreeOptions,
12
12
  BTNCallback,
13
- BTNKey,
14
13
  BTNodeEntry,
15
14
  BTNodeExemplar,
16
- BTNodeKeyOrNode
15
+ BTNodeKeyOrNode,
17
16
  } from '../../types';
18
17
  import {
19
18
  BinaryTreeNested,
20
19
  BinaryTreePrintOptions,
21
20
  BiTreeDeleteResult,
22
21
  DFSOrderPattern,
22
+ EntryCallback,
23
23
  FamilyPosition,
24
24
  IterationType,
25
25
  NodeDisplayLayout
@@ -27,20 +27,21 @@ import {
27
27
  import { IBinaryTree } from '../../interfaces';
28
28
  import { trampoline } from '../../utils';
29
29
  import { Queue } from '../queue';
30
+ import { IterableEntryBase } from "../base";
30
31
 
31
32
  /**
32
33
  * Represents a node in a binary tree.
33
34
  * @template V - The type of data stored in the node.
34
35
  * @template N - The type of the family relationship in the binary tree.
35
36
  */
36
- export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>> {
37
- key: BTNKey;
37
+ export class BinaryTreeNode<K = any, V = any, N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>> {
38
+ key: K;
38
39
 
39
40
  value?: V;
40
41
 
41
42
  parent?: N;
42
43
 
43
- constructor(key: BTNKey, value?: V) {
44
+ constructor(key: K, value?: V) {
44
45
  this.key = key;
45
46
  this.value = value;
46
47
  }
@@ -97,14 +98,11 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
97
98
  * 3. Depth and Height: Depth is the number of edges from the root to a node; height is the maximum depth in the tree.
98
99
  * 4. Subtrees: Each child of a node forms the root of a subtree.
99
100
  * 5. Leaf Nodes: Nodes without children are leaves.
100
- * 6. Internal Nodes: Nodes with at least one child are internal.
101
- * 7. Balanced Trees: The heights of the left and right subtrees of any node differ by no more than one.
102
- * 8. Full Trees: Every node has either 0 or 2 children.
103
- * 9. Complete Trees: All levels are fully filled except possibly the last, filled from left to right.
104
101
  */
105
- export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>, TREE extends BinaryTree<V, N, TREE> = BinaryTree<V, N, BinaryTreeNested<V, N>>>
106
- implements IBinaryTree<V, N, TREE> {
107
102
 
103
+ export class BinaryTree<K = any, V = any, N extends BinaryTreeNode<K, V, N> = BinaryTreeNode<K, V, BinaryTreeNodeNested<K, V>>, TREE extends BinaryTree<K, V, N, TREE> = BinaryTree<K, V, N, BinaryTreeNested<K, V, N>>> extends IterableEntryBase<K, V | undefined>
104
+
105
+ implements IBinaryTree<K, V, N, TREE> {
108
106
  iterationType = IterationType.ITERATIVE
109
107
 
110
108
  /**
@@ -116,13 +114,16 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
116
114
  * `Partial<BinaryTreeOptions>`, which means that not all properties of `BinaryTreeOptions` are
117
115
  * required.
118
116
  */
119
- constructor(elements?: Iterable<BTNodeExemplar<V, N>>, options?: Partial<BinaryTreeOptions>) {
120
-
117
+ constructor(elements?: Iterable<BTNodeExemplar<K, V, N>>, options?: Partial<BinaryTreeOptions<K>>) {
118
+ super();
121
119
  if (options) {
122
- const { iterationType } = options;
120
+ const { iterationType, extractor } = options;
123
121
  if (iterationType) {
124
122
  this.iterationType = iterationType;
125
123
  }
124
+ if (extractor) {
125
+ this._extractor = extractor;
126
+ }
126
127
  }
127
128
 
128
129
  this._size = 0;
@@ -130,6 +131,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
130
131
  if (elements) this.addMany(elements);
131
132
  }
132
133
 
134
+ protected _extractor = (key: K) => Number(key)
135
+
136
+ get extractor() {
137
+ return this._extractor;
138
+ }
139
+
133
140
  protected _root?: N | null;
134
141
 
135
142
  get root(): N | null | undefined {
@@ -144,12 +151,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
144
151
 
145
152
  /**
146
153
  * Creates a new instance of BinaryTreeNode with the given key and value.
147
- * @param {BTNKey} key - The key for the new node.
154
+ * @param {K} key - The key for the new node.
148
155
  * @param {V} value - The value for the new node.
149
156
  * @returns {N} - The newly created BinaryTreeNode.
150
157
  */
151
- createNode(key: BTNKey, value?: V): N {
152
- return new BinaryTreeNode<V, N>(key, value) as N;
158
+ createNode(key: K, value?: V): N {
159
+ return new BinaryTreeNode<K, V, N>(key, value) as N;
153
160
  }
154
161
 
155
162
  /**
@@ -159,27 +166,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
159
166
  * you can provide only a subset of the properties defined in the `BinaryTreeOptions` interface.
160
167
  * @returns a new instance of a binary tree.
161
168
  */
162
- createTree(options?: Partial<BinaryTreeOptions>): TREE {
163
- return new BinaryTree<V, N, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
169
+ createTree(options?: Partial<BinaryTreeOptions<K>>): TREE {
170
+ return new BinaryTree<K, V, N, TREE>([], { iterationType: this.iterationType, ...options }) as TREE;
164
171
  }
165
172
 
166
173
  /**
167
174
  * The function "isNode" checks if an exemplar is an instance of the BinaryTreeNode class.
168
- * @param exemplar - The `exemplar` parameter is a variable of type `BTNodeExemplar<V, N>`.
175
+ * @param exemplar - The `exemplar` parameter is a variable of type `BTNodeExemplar<K, V,N>`.
169
176
  * @returns a boolean value indicating whether the exemplar is an instance of the class N.
170
177
  */
171
- isNode(exemplar: BTNodeExemplar<V, N>): exemplar is N {
178
+ isNode(exemplar: BTNodeExemplar<K, V, N>): exemplar is N {
172
179
  return exemplar instanceof BinaryTreeNode;
173
180
  }
174
181
 
175
182
  /**
176
- * The function `exemplarToNode` converts an exemplar of a binary tree node into an actual node
177
- * object.
178
- * @param exemplar - BTNodeExemplar<V, N> - A generic type representing the exemplar parameter of the
179
- * function. It can be any type.
180
- * @returns a value of type `N` (which represents a node), or `null`, or `undefined`.
183
+ * The function `exemplarToNode` converts an exemplar object into a node object.
184
+ * @param exemplar - The `exemplar` parameter is of type `BTNodeExemplar<K, V, N>`.
185
+ * @param {V} [value] - The `value` parameter is an optional value that can be passed to the
186
+ * `exemplarToNode` function. It represents the value associated with the exemplar node. If no value
187
+ * is provided, it will be `undefined`.
188
+ * @returns a value of type N (node), or null, or undefined.
181
189
  */
182
- exemplarToNode(exemplar: BTNodeExemplar<V, N>): N | null | undefined {
190
+ exemplarToNode(exemplar: BTNodeExemplar<K, V, N>, value?: V): N | null | undefined {
183
191
  if (exemplar === undefined) return;
184
192
 
185
193
  let node: N | null | undefined;
@@ -196,8 +204,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
196
204
  }
197
205
  } else if (this.isNode(exemplar)) {
198
206
  node = exemplar;
199
- } else if (this.isNodeKey(exemplar)) {
200
- node = this.createNode(exemplar);
207
+ } else if (this.isNotNodeInstance(exemplar)) {
208
+ node = this.createNode(exemplar, value);
201
209
  } else {
202
210
  return;
203
211
  }
@@ -206,11 +214,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
206
214
 
207
215
  /**
208
216
  * The function checks if a given value is an entry in a binary tree node.
209
- * @param kne - BTNodeExemplar<V, N> - A generic type representing a node in a binary tree. It has
217
+ * @param kne - BTNodeExemplar<K, V,N> - A generic type representing a node in a binary tree. It has
210
218
  * two type parameters V and N, representing the value and node type respectively.
211
219
  * @returns a boolean value.
212
220
  */
213
- isEntry(kne: BTNodeExemplar<V, N>): kne is BTNodeEntry<V> {
221
+ isEntry(kne: BTNodeExemplar<K, V, N>): kne is BTNodeEntry<K, V> {
214
222
  return Array.isArray(kne) && kne.length === 2;
215
223
  }
216
224
 
@@ -223,88 +231,116 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
223
231
  * Time Complexity O(log n) - O(n)
224
232
  * Space Complexity O(1)
225
233
  *
226
- * The `add` function adds a new node to a binary tree, either by key or by providing a node object.
227
- * @param keyOrNodeOrEntry - The parameter `keyOrNodeOrEntry` can be one of the following:
228
- * @returns The function `add` returns the inserted node (`N`), `null`, or `undefined`.
229
- */
230
- add(keyOrNodeOrEntry: BTNodeExemplar<V, N>): N | null | undefined {
231
-
232
- let inserted: N | null | undefined;
233
- const newNode = this.exemplarToNode(keyOrNodeOrEntry);
234
+ * The `add` function adds a new node to a binary tree, either by creating a new node or replacing an
235
+ * existing node with the same key.
236
+ * @param keyOrNodeOrEntry - The `keyOrNodeOrEntry` parameter can be one of the following:
237
+ * @param {V} [value] - The value to be inserted into the binary tree.
238
+ * @returns The function `add` returns either a node (`N`), `null`, or `undefined`.
239
+ */
240
+ add(keyOrNodeOrEntry: BTNodeExemplar<K, V, N>, value?: V): N | null | undefined {
241
+ const newNode = this.exemplarToNode(keyOrNodeOrEntry, value);
234
242
  if (newNode === undefined) return;
235
243
 
236
- const _bfs = (root: N, newNode: N | null): N | undefined | null => {
237
- const queue = new Queue<N>([root]);
238
- while (queue.size > 0) {
239
- const cur = queue.shift()!;
240
- if (newNode && cur.key === newNode.key) {
241
- this._replaceNode(cur, newNode);
242
- return newNode;
243
- }
244
- const inserted = this._addTo(newNode, cur);
245
- if (inserted !== undefined) return inserted;
246
- if (cur.left) queue.push(cur.left);
247
- if (cur.right) queue.push(cur.right);
244
+ // If the tree is empty, directly set the new node as the root node
245
+ if (!this.root) {
246
+ this._root = newNode;
247
+ this._size = 1;
248
+ return newNode;
249
+ }
250
+
251
+ const queue = new Queue<N>([this.root]);
252
+ let potentialParent: N | undefined; // Record the parent node of the potential insertion location
253
+
254
+ while (queue.size > 0) {
255
+ const cur = queue.shift();
256
+
257
+ if (!cur) continue;
258
+
259
+ // Check for duplicate keys when newNode is not null
260
+ if (newNode !== null && cur.key === newNode.key) {
261
+ this._replaceNode(cur, newNode);
262
+ return newNode; // If duplicate keys are found, no insertion is performed
248
263
  }
249
- };
250
264
 
251
- if (this.root) {
252
- inserted = _bfs(this.root, newNode);
253
- } else {
254
- this._setRoot(newNode);
255
- if (newNode) {
256
- this._size = 1;
257
- } else {
258
- this._size = 0;
265
+ // Record the first possible insertion location found
266
+ if (potentialParent === undefined && (cur.left === undefined || cur.right === undefined)) {
267
+ potentialParent = cur;
268
+ }
269
+
270
+ // Continue traversing the left and right subtrees
271
+ if (cur.left !== null) {
272
+ cur.left && queue.push(cur.left);
273
+ }
274
+ if (cur.right !== null) {
275
+ cur.right && queue.push(cur.right);
259
276
  }
260
- inserted = this.root;
261
277
  }
262
- return inserted;
278
+
279
+ // At the end of the traversal, if the insertion position is found, insert
280
+ if (potentialParent) {
281
+ if (potentialParent.left === undefined) {
282
+ potentialParent.left = newNode;
283
+ } else if (potentialParent.right === undefined) {
284
+ potentialParent.right = newNode;
285
+ }
286
+ this._size++;
287
+ return newNode;
288
+ }
289
+
290
+ return undefined; // If the insertion position cannot be found, return undefined
263
291
  }
264
292
 
293
+
265
294
  /**
266
295
  * Time Complexity: O(k log n) - O(k * n)
267
296
  * Space Complexity: O(1)
268
297
  * 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.
269
298
  */
270
299
 
271
-
272
300
  /**
273
301
  * Time Complexity: O(k log n) - O(k * n)
274
302
  * Space Complexity: O(1)
275
303
  *
276
- * The function `addMany` takes in an iterable of `BTNodeExemplar` objects, adds each object to the
277
- * current instance, and returns an array of the inserted nodes.
278
- * @param nodes - The `nodes` parameter is an iterable (such as an array or a set) of
279
- * `BTNodeExemplar<V, N>` objects.
280
- * @returns The function `addMany` returns an array of values, where each value is either of type
281
- * `N`, `null`, or `undefined`.
282
- */
283
- addMany(nodes: Iterable<BTNodeExemplar<V, N>>): (N | null | undefined)[] {
304
+ * The `addMany` function takes in a collection of nodes and an optional collection of values, and
305
+ * adds each node with its corresponding value to the data structure.
306
+ * @param nodes - An iterable collection of BTNodeExemplar objects.
307
+ * @param [values] - An optional iterable of values that will be assigned to each node being added.
308
+ * @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
309
+ */
310
+ addMany(nodes: Iterable<BTNodeExemplar<K, V, N>>, values?: Iterable<V | undefined>): (N | null | undefined)[] {
284
311
  // TODO not sure addMany not be run multi times
285
312
  const inserted: (N | null | undefined)[] = [];
313
+
314
+ let valuesIterator: Iterator<V | undefined> | undefined;
315
+ if (values) {
316
+ valuesIterator = values[Symbol.iterator]();
317
+ }
318
+
286
319
  for (const kne of nodes) {
287
- inserted.push(this.add(kne));
320
+ let value: V | undefined | null = undefined;
321
+
322
+ if (valuesIterator) {
323
+ const valueResult = valuesIterator.next();
324
+ if (!valueResult.done) {
325
+ value = valueResult.value;
326
+ }
327
+ }
328
+
329
+ inserted.push(this.add(kne, value));
288
330
  }
331
+
289
332
  return inserted;
290
333
  }
291
334
 
292
- /**
293
- * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
294
- * Space Complexity: O(1)
295
- */
296
335
 
297
336
  /**
298
337
  * Time Complexity: O(k * n) "n" is the number of nodes in the tree, and "k" is the number of keys to be inserted.
299
338
  * Space Complexity: O(1)
300
- *
301
- * The `refill` function clears the current collection and adds new nodes, keys, or entries to it.
302
- * @param nodesOrKeysOrEntries - The parameter `nodesOrKeysOrEntries` is an iterable object that can
303
- * contain either `BTNodeExemplar` objects, keys, or entries.
304
339
  */
305
- refill(nodesOrKeysOrEntries: Iterable<BTNodeExemplar<V, N>>): void {
340
+
341
+ refill(nodesOrKeysOrEntries: Iterable<BTNodeExemplar<K, V, N>>, values?: Iterable<V | undefined>): void {
306
342
  this.clear();
307
- this.addMany(nodesOrKeysOrEntries);
343
+ this.addMany(nodesOrKeysOrEntries, values);
308
344
  }
309
345
 
310
346
  /**
@@ -312,7 +348,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
312
348
  * Space Complexity: O(1)
313
349
  */
314
350
 
315
- delete<C extends BTNCallback<N, BTNKey>>(identifier: BTNKey, callback?: C): BiTreeDeleteResult<N>[];
351
+ delete<C extends BTNCallback<N, K>>(identifier: K, callback?: C): BiTreeDeleteResult<N>[];
316
352
 
317
353
  delete<C extends BTNCallback<N, N>>(identifier: N | null | undefined, callback?: C): BiTreeDeleteResult<N>[];
318
354
 
@@ -393,15 +429,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
393
429
  * Space Complexity: O(1)
394
430
  *
395
431
  * The function calculates the depth of a given node in a binary tree.
396
- * @param {BTNKey | N | null | undefined} distNode - The `distNode` parameter represents the node in
397
- * the binary tree whose depth we want to find. It can be of type `BTNKey`, `N`, `null`, or
432
+ * @param {K | N | null | undefined} distNode - The `distNode` parameter represents the node in
433
+ * the binary tree whose depth we want to find. It can be of type `K`, `N`, `null`, or
398
434
  * `undefined`.
399
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
400
- * from which we want to calculate the depth. It can be either a `BTNKey` (binary tree node key) or
435
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
436
+ * from which we want to calculate the depth. It can be either a `K` (binary tree node key) or
401
437
  * `N` (binary tree node) or `null` or `undefined`. If no value is provided for `beginRoot
402
438
  * @returns the depth of the `distNode` relative to the `beginRoot`.
403
439
  */
404
- getDepth(distNode: BTNodeKeyOrNode<N>, beginRoot: BTNodeKeyOrNode<N> = this.root): number {
440
+ getDepth(distNode: BTNodeKeyOrNode<K, N>, beginRoot: BTNodeKeyOrNode<K, N> = this.root): number {
405
441
  distNode = this.ensureNode(distNode);
406
442
  beginRoot = this.ensureNode(beginRoot);
407
443
  let depth = 0;
@@ -426,15 +462,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
426
462
  *
427
463
  * The function `getHeight` calculates the maximum height of a binary tree using either recursive or
428
464
  * iterative traversal.
429
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
465
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
430
466
  * starting node of the binary tree from which we want to calculate the height. It can be of type
431
- * `BTNKey`, `N`, `null`, or `undefined`. If not provided, it defaults to `this.root`.
467
+ * `K`, `N`, `null`, or `undefined`. If not provided, it defaults to `this.root`.
432
468
  * @param iterationType - The `iterationType` parameter is used to determine whether to calculate the
433
469
  * height of the tree using a recursive approach or an iterative approach. It can have two possible
434
470
  * values:
435
471
  * @returns the height of the binary tree.
436
472
  */
437
- getHeight(beginRoot: BTNodeKeyOrNode<N> = this.root, iterationType = this.iterationType): number {
473
+ getHeight(beginRoot: BTNodeKeyOrNode<K, N> = this.root, iterationType = this.iterationType): number {
438
474
  beginRoot = this.ensureNode(beginRoot);
439
475
  if (!beginRoot) return -1;
440
476
 
@@ -476,14 +512,14 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
476
512
  *
477
513
  * The `getMinHeight` function calculates the minimum height of a binary tree using either a
478
514
  * recursive or iterative approach.
479
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
515
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
480
516
  * starting node of the binary tree from which we want to calculate the minimum height. It can be of
481
- * type `BTNKey`, `N`, `null`, or `undefined`. If no value is provided, it defaults to `this.root`.
517
+ * type `K`, `N`, `null`, or `undefined`. If no value is provided, it defaults to `this.root`.
482
518
  * @param iterationType - The `iterationType` parameter is used to determine the method of iteration
483
519
  * to calculate the minimum height of a binary tree. It can have two possible values:
484
520
  * @returns The function `getMinHeight` returns the minimum height of a binary tree.
485
521
  */
486
- getMinHeight(beginRoot: BTNodeKeyOrNode<N> = this.root, iterationType = this.iterationType): number {
522
+ getMinHeight(beginRoot: BTNodeKeyOrNode<K, N> = this.root, iterationType = this.iterationType): number {
487
523
  beginRoot = this.ensureNode(beginRoot);
488
524
  if (!beginRoot) return -1;
489
525
 
@@ -538,12 +574,12 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
538
574
  *
539
575
  * The function checks if a binary tree is perfectly balanced by comparing the minimum height and the
540
576
  * height of the tree.
541
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
542
- * for calculating the height and minimum height of a binary tree. It can be either a `BTNKey` (a key
577
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
578
+ * for calculating the height and minimum height of a binary tree. It can be either a `K` (a key
543
579
  * value of a binary tree node), `N` (a node of a binary tree), `null`, or `undefined`. If
544
580
  * @returns a boolean value.
545
581
  */
546
- isPerfectlyBalanced(beginRoot: BTNodeKeyOrNode<N> = this.root): boolean {
582
+ isPerfectlyBalanced(beginRoot: BTNodeKeyOrNode<K, N> = this.root): boolean {
547
583
  return this.getMinHeight(beginRoot) + 1 >= this.getHeight(beginRoot);
548
584
  }
549
585
 
@@ -552,11 +588,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
552
588
  * Space Complexity: O(log n)
553
589
  */
554
590
 
555
- getNodes<C extends BTNCallback<N, BTNKey>>(
556
- identifier: BTNKey,
591
+ getNodes<C extends BTNCallback<N, K>>(
592
+ identifier: K,
557
593
  callback?: C,
558
594
  onlyOne?: boolean,
559
- beginRoot?: BTNodeKeyOrNode<N>,
595
+ beginRoot?: BTNodeKeyOrNode<K, N>,
560
596
  iterationType?: IterationType
561
597
  ): N[];
562
598
 
@@ -564,7 +600,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
564
600
  identifier: N | null | undefined,
565
601
  callback?: C,
566
602
  onlyOne?: boolean,
567
- beginRoot?: BTNodeKeyOrNode<N>,
603
+ beginRoot?: BTNodeKeyOrNode<K, N>,
568
604
  iterationType?: IterationType
569
605
  ): N[];
570
606
 
@@ -572,7 +608,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
572
608
  identifier: ReturnType<C>,
573
609
  callback: C,
574
610
  onlyOne?: boolean,
575
- beginRoot?: BTNodeKeyOrNode<N>,
611
+ beginRoot?: BTNodeKeyOrNode<K, N>,
576
612
  iterationType?: IterationType
577
613
  ): N[];
578
614
 
@@ -594,7 +630,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
594
630
  * matches the identifier. If set to true, the function will stop iterating once it finds a matching
595
631
  * node and return that node. If set to false (default), the function will continue iterating and
596
632
  * return all nodes that match the identifier.
597
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
633
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
598
634
  * starting node for the traversal. It can be either a key, a node object, or `null`/`undefined`. If
599
635
  * it is `null` or `undefined`, an empty array will be returned.
600
636
  * @param iterationType - The `iterationType` parameter determines the type of iteration used to
@@ -605,7 +641,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
605
641
  identifier: ReturnType<C> | null | undefined,
606
642
  callback: C = this._defaultOneParamCallback as C,
607
643
  onlyOne = false,
608
- beginRoot: BTNodeKeyOrNode<N> = this.root,
644
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
609
645
  iterationType = this.iterationType
610
646
  ): N[] {
611
647
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
@@ -650,24 +686,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
650
686
  * Space Complexity: O(log n).
651
687
  */
652
688
 
653
- has<C extends BTNCallback<N, BTNKey>>(
654
- identifier: BTNKey,
689
+ has<C extends BTNCallback<N, K>>(
690
+ identifier: K,
655
691
  callback?: C,
656
- beginRoot?: BTNodeKeyOrNode<N>,
692
+ beginRoot?: BTNodeKeyOrNode<K, N>,
657
693
  iterationType?: IterationType
658
694
  ): boolean;
659
695
 
660
696
  has<C extends BTNCallback<N, N>>(
661
697
  identifier: N | null | undefined,
662
698
  callback?: C,
663
- beginRoot?: BTNodeKeyOrNode<N>,
699
+ beginRoot?: BTNodeKeyOrNode<K, N>,
664
700
  iterationType?: IterationType
665
701
  ): boolean;
666
702
 
667
703
  has<C extends BTNCallback<N>>(
668
704
  identifier: ReturnType<C> | null | undefined,
669
705
  callback: C,
670
- beginRoot?: BTNodeKeyOrNode<N>,
706
+ beginRoot?: BTNodeKeyOrNode<K, N>,
671
707
  iterationType?: IterationType
672
708
  ): boolean;
673
709
 
@@ -683,8 +719,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
683
719
  * the binary tree. It is used to filter the nodes based on certain conditions. The `callback`
684
720
  * function should return a boolean value indicating whether the node should be included in the
685
721
  * result or not.
686
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
687
- * for the search in the binary tree. It can be specified as a `BTNKey` (a unique identifier for a
722
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
723
+ * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a
688
724
  * node in the binary tree), a node object (`N`), or `null`/`undefined` to start the search from
689
725
  * @param iterationType - The `iterationType` parameter is a variable that determines the type of
690
726
  * iteration to be performed on the binary tree. It is used to specify whether the iteration should
@@ -694,7 +730,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
694
730
  has<C extends BTNCallback<N>>(
695
731
  identifier: ReturnType<C> | null | undefined,
696
732
  callback: C = this._defaultOneParamCallback as C,
697
- beginRoot: BTNodeKeyOrNode<N> = this.root,
733
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
698
734
  iterationType = this.iterationType
699
735
  ): boolean {
700
736
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
@@ -708,24 +744,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
708
744
  * Space Complexity: O(log n).
709
745
  */
710
746
 
711
- getNode<C extends BTNCallback<N, BTNKey>>(
712
- identifier: BTNKey,
747
+ getNode<C extends BTNCallback<N, K>>(
748
+ identifier: K,
713
749
  callback?: C,
714
- beginRoot?: BTNodeKeyOrNode<N>,
750
+ beginRoot?: BTNodeKeyOrNode<K, N>,
715
751
  iterationType?: IterationType
716
752
  ): N | null | undefined;
717
753
 
718
754
  getNode<C extends BTNCallback<N, N>>(
719
755
  identifier: N | null | undefined,
720
756
  callback?: C,
721
- beginRoot?: BTNodeKeyOrNode<N>,
757
+ beginRoot?: BTNodeKeyOrNode<K, N>,
722
758
  iterationType?: IterationType
723
759
  ): N | null | undefined;
724
760
 
725
761
  getNode<C extends BTNCallback<N>>(
726
762
  identifier: ReturnType<C>,
727
763
  callback: C,
728
- beginRoot?: BTNodeKeyOrNode<N>,
764
+ beginRoot?: BTNodeKeyOrNode<K, N>,
729
765
  iterationType?: IterationType
730
766
  ): N | null | undefined;
731
767
 
@@ -742,7 +778,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
742
778
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
743
779
  * the binary tree. It is used to determine if a node matches the given identifier. The `callback`
744
780
  * function should take a single parameter of type `N` (the type of the nodes in the binary tree) and
745
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
781
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
746
782
  * for searching the binary tree. It can be either a key value, a node object, or `null`/`undefined`.
747
783
  * If `null` or `undefined` is passed, the search will start from the root of the binary tree.
748
784
  * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
@@ -753,7 +789,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
753
789
  getNode<C extends BTNCallback<N>>(
754
790
  identifier: ReturnType<C> | null | undefined,
755
791
  callback: C = this._defaultOneParamCallback as C,
756
- beginRoot: BTNodeKeyOrNode<N> = this.root,
792
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
757
793
  iterationType = this.iterationType
758
794
  ): N | null | undefined {
759
795
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
@@ -773,7 +809,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
773
809
  *
774
810
  * The function `getNodeByKey` searches for a node in a binary tree by its key, using either
775
811
  * recursive or iterative iteration.
776
- * @param {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree.
812
+ * @param {K} key - The `key` parameter is the key value that we are searching for in the tree.
777
813
  * It is used to find the node with the matching key value.
778
814
  * @param iterationType - The `iterationType` parameter is used to determine whether the search for
779
815
  * the node with the given key should be performed iteratively or recursively. It has two possible
@@ -781,7 +817,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
781
817
  * @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
782
818
  * found in the binary tree. If no node is found, it returns `undefined`.
783
819
  */
784
- getNodeByKey(key: BTNKey, iterationType = IterationType.ITERATIVE): N | undefined {
820
+ getNodeByKey(key: K, iterationType = IterationType.ITERATIVE): N | undefined {
785
821
  if (!this.root) return undefined;
786
822
  if (iterationType === IterationType.RECURSIVE) {
787
823
  const _dfs = (cur: N): N | undefined => {
@@ -814,7 +850,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
814
850
  /**
815
851
  * The function `ensureNode` returns the node corresponding to the given key if it is a valid node
816
852
  * key, otherwise it returns the key itself.
817
- * @param {BTNKey | N | null | undefined} key - The `key` parameter can be of type `BTNKey`, `N`,
853
+ * @param {K | N | null | undefined} key - The `key` parameter can be of type `K`, `N`,
818
854
  * `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
819
855
  * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
820
856
  * type of iteration to be used when searching for a node by key. It has a default value of
@@ -822,28 +858,28 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
822
858
  * @returns either the node corresponding to the given key if it is a valid node key, or the key
823
859
  * itself if it is not a valid node key.
824
860
  */
825
- ensureNode(key: BTNodeKeyOrNode<N>, iterationType = IterationType.ITERATIVE): N | null | undefined {
826
- return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
861
+ ensureNode(key: BTNodeKeyOrNode<K, N>, iterationType = IterationType.ITERATIVE): N | null | undefined {
862
+ return this.isNotNodeInstance(key) ? this.getNodeByKey(key, iterationType) : key;
827
863
  }
828
864
 
829
- get<C extends BTNCallback<N, BTNKey>>(
830
- identifier: BTNKey,
865
+ get<C extends BTNCallback<N, K>>(
866
+ identifier: K,
831
867
  callback?: C,
832
- beginRoot?: BTNodeKeyOrNode<N>,
868
+ beginRoot?: BTNodeKeyOrNode<K, N>,
833
869
  iterationType?: IterationType
834
870
  ): V | undefined;
835
871
 
836
872
  get<C extends BTNCallback<N, N>>(
837
873
  identifier: N | null | undefined,
838
874
  callback?: C,
839
- beginRoot?: BTNodeKeyOrNode<N>,
875
+ beginRoot?: BTNodeKeyOrNode<K, N>,
840
876
  iterationType?: IterationType
841
877
  ): V | undefined;
842
878
 
843
879
  get<C extends BTNCallback<N>>(
844
880
  identifier: ReturnType<C>,
845
881
  callback: C,
846
- beginRoot?: BTNodeKeyOrNode<N>,
882
+ beginRoot?: BTNodeKeyOrNode<K, N>,
847
883
  iterationType?: IterationType
848
884
  ): V | undefined;
849
885
 
@@ -860,8 +896,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
860
896
  * the binary tree. It is used to determine whether a node matches the given identifier. The callback
861
897
  * function should return a value that can be compared to the identifier to determine if it is a
862
898
  * match.
863
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
864
- * for the search in the binary tree. It can be specified as a `BTNKey` (a unique identifier for a
899
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
900
+ * for the search in the binary tree. It can be specified as a `K` (a unique identifier for a
865
901
  * node), a node object of type `N`, or `null`/`undefined` to start the search from the root of
866
902
  * @param iterationType - The `iterationType` parameter is used to specify the type of iteration to
867
903
  * be performed when searching for a node in the binary tree. It is an optional parameter with a
@@ -872,7 +908,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
872
908
  get<C extends BTNCallback<N>>(
873
909
  identifier: ReturnType<C> | null | undefined,
874
910
  callback: C = this._defaultOneParamCallback as C,
875
- beginRoot: BTNodeKeyOrNode<N> = this.root,
911
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
876
912
  iterationType = this.iterationType
877
913
  ): V | undefined {
878
914
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
@@ -908,15 +944,15 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
908
944
  *
909
945
  * The function `getPathToRoot` returns an array of nodes from a given node to the root of a tree
910
946
  * structure, with the option to reverse the order of the nodes.
911
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
912
- * starting node from which you want to find the path to the root. It can be of type `BTNKey`, `N`,
947
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
948
+ * starting node from which you want to find the path to the root. It can be of type `K`, `N`,
913
949
  * `null`, or `undefined`.
914
950
  * @param [isReverse=true] - The `isReverse` parameter is a boolean flag that determines whether the
915
951
  * resulting path should be reversed or not. If `isReverse` is set to `true`, the path will be
916
952
  * reversed before returning it. If `isReverse` is set to `false`, the path will be returned as is
917
953
  * @returns The function `getPathToRoot` returns an array of nodes (`N[]`).
918
954
  */
919
- getPathToRoot(beginRoot: BTNodeKeyOrNode<N>, isReverse = true): N[] {
955
+ getPathToRoot(beginRoot: BTNodeKeyOrNode<K, N>, isReverse = true): N[] {
920
956
  // TODO to support get path through passing key
921
957
  const result: N[] = [];
922
958
  beginRoot = this.ensureNode(beginRoot);
@@ -944,8 +980,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
944
980
  *
945
981
  * The function `getLeftMost` returns the leftmost node in a binary tree, either recursively or
946
982
  * iteratively.
947
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
948
- * for finding the leftmost node in a binary tree. It can be either a `BTNKey` (a key value), `N` (a
983
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting point
984
+ * for finding the leftmost node in a binary tree. It can be either a `K` (a key value), `N` (a
949
985
  * node), `null`, or `undefined`. If not provided, it defaults to `this.root`,
950
986
  * @param iterationType - The `iterationType` parameter is used to determine the type of iteration to
951
987
  * be performed when finding the leftmost node in a binary tree. It can have two possible values:
@@ -953,7 +989,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
953
989
  * is no leftmost node, it returns `null` or `undefined` depending on the input.
954
990
  */
955
991
  getLeftMost(
956
- beginRoot: BTNodeKeyOrNode<N> = this.root,
992
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
957
993
  iterationType = this.iterationType
958
994
  ): N | null | undefined {
959
995
  beginRoot = this.ensureNode(beginRoot);
@@ -989,8 +1025,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
989
1025
  *
990
1026
  * The function `getRightMost` returns the rightmost node in a binary tree, either recursively or
991
1027
  * iteratively.
992
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
993
- * starting node from which we want to find the rightmost node. It can be of type `BTNKey`, `N`,
1028
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1029
+ * starting node from which we want to find the rightmost node. It can be of type `K`, `N`,
994
1030
  * `null`, or `undefined`. If not provided, it defaults to `this.root`, which is a property of the
995
1031
  * current object.
996
1032
  * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
@@ -999,7 +1035,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
999
1035
  * is no rightmost node, it returns `null` or `undefined`, depending on the input.
1000
1036
  */
1001
1037
  getRightMost(
1002
- beginRoot: BTNodeKeyOrNode<N> = this.root,
1038
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
1003
1039
  iterationType = this.iterationType
1004
1040
  ): N | null | undefined {
1005
1041
  // TODO support get right most by passing key in
@@ -1034,23 +1070,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1034
1070
  * Space Complexity: O(1)
1035
1071
  *
1036
1072
  * The function `isSubtreeBST` checks if a given binary tree is a valid binary search tree.
1037
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the root
1073
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the root
1038
1074
  * node of the binary search tree (BST) that you want to check if it is a subtree of another BST.
1039
1075
  * @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
1040
1076
  * type of iteration to use when checking if a subtree is a binary search tree (BST). It can have two
1041
1077
  * possible values:
1042
1078
  * @returns a boolean value.
1043
1079
  */
1044
- isSubtreeBST(beginRoot: BTNodeKeyOrNode<N>, iterationType = this.iterationType): boolean {
1080
+ isSubtreeBST(beginRoot: BTNodeKeyOrNode<K, N>, iterationType = this.iterationType): boolean {
1045
1081
  // TODO there is a bug
1046
1082
  beginRoot = this.ensureNode(beginRoot);
1047
1083
  if (!beginRoot) return true;
1048
1084
 
1049
1085
  if (iterationType === IterationType.RECURSIVE) {
1050
- const dfs = (cur: N | null | undefined, min: BTNKey, max: BTNKey): boolean => {
1086
+ const dfs = (cur: N | null | undefined, min: number, max: number): boolean => {
1051
1087
  if (!cur) return true;
1052
- if (cur.key <= min || cur.key >= max) return false;
1053
- return dfs(cur.left, min, cur.key) && dfs(cur.right, cur.key, max);
1088
+ const numKey = this.extractor(cur.key);
1089
+ if (numKey <= min || numKey >= max) return false;
1090
+ return dfs(cur.left, min, numKey) && dfs(cur.right, numKey, max);
1054
1091
  };
1055
1092
 
1056
1093
  return dfs(beginRoot, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
@@ -1064,8 +1101,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1064
1101
  curr = curr.left;
1065
1102
  }
1066
1103
  curr = stack.pop()!;
1067
- if (!curr || prev >= curr.key) return false;
1068
- prev = curr.key;
1104
+ const numKey = this.extractor(curr.key);
1105
+ if (!curr || prev >= numKey) return false;
1106
+ prev = numKey;
1069
1107
  curr = curr.right;
1070
1108
  }
1071
1109
  return true;
@@ -1100,21 +1138,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1100
1138
 
1101
1139
  subTreeTraverse<C extends BTNCallback<N>>(
1102
1140
  callback?: C,
1103
- beginRoot?: BTNodeKeyOrNode<N>,
1141
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1104
1142
  iterationType?: IterationType,
1105
1143
  includeNull?: false
1106
1144
  ): ReturnType<C>[];
1107
1145
 
1108
1146
  subTreeTraverse<C extends BTNCallback<N>>(
1109
1147
  callback?: C,
1110
- beginRoot?: BTNodeKeyOrNode<N>,
1148
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1111
1149
  iterationType?: IterationType,
1112
1150
  includeNull?: undefined
1113
1151
  ): ReturnType<C>[];
1114
1152
 
1115
1153
  subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
1116
1154
  callback?: C,
1117
- beginRoot?: BTNodeKeyOrNode<N>,
1155
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1118
1156
  iterationType?: IterationType,
1119
1157
  includeNull?: true
1120
1158
  ): ReturnType<C>[];
@@ -1128,8 +1166,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1128
1166
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1129
1167
  * the subtree traversal. It takes a single parameter, which is the current node being traversed, and
1130
1168
  * returns a value of any type.
1131
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1132
- * starting node or key from which the subtree traversal should begin. It can be of type `BTNKey`,
1169
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1170
+ * starting node or key from which the subtree traversal should begin. It can be of type `K`,
1133
1171
  * `N`, `null`, or `undefined`. If not provided, the `root` property of the current object is used as
1134
1172
  * the default value.
1135
1173
  * @param iterationType - The `iterationType` parameter determines the type of traversal to be
@@ -1143,7 +1181,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1143
1181
  */
1144
1182
  subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
1145
1183
  callback: C = this._defaultOneParamCallback as C,
1146
- beginRoot: BTNodeKeyOrNode<N> = this.root,
1184
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
1147
1185
  iterationType = this.iterationType,
1148
1186
  includeNull = false
1149
1187
  ): ReturnType<C>[] {
@@ -1198,8 +1236,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1198
1236
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
1199
1237
  * @returns a boolean value.
1200
1238
  */
1201
- isRealNode(node: any): node is N {
1202
- return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
1239
+ isRealNode(node: BTNodeExemplar<K, V, N>): node is N {
1240
+ return node instanceof BinaryTreeNode && String(node.key) !== 'NaN';
1203
1241
  }
1204
1242
 
1205
1243
  /**
@@ -1207,8 +1245,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1207
1245
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
1208
1246
  * @returns a boolean value.
1209
1247
  */
1210
- isNIL(node: any) {
1211
- return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
1248
+ isNIL(node: BTNodeExemplar<K, V, N>) {
1249
+ return node instanceof BinaryTreeNode && String(node.key) === 'NaN';
1212
1250
  }
1213
1251
 
1214
1252
  /**
@@ -1216,24 +1254,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1216
1254
  * @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
1217
1255
  * @returns a boolean value.
1218
1256
  */
1219
- isNodeOrNull(node: any): node is N | null {
1257
+ isNodeOrNull(node: BTNodeExemplar<K, V, N>): node is N | null {
1220
1258
  return this.isRealNode(node) || node === null;
1221
1259
  }
1222
1260
 
1223
1261
  /**
1224
- * The function "isNodeKey" checks if a potential key is a number.
1262
+ * The function "isNotNodeInstance" checks if a potential key is a K.
1225
1263
  * @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
1226
1264
  * data type.
1227
1265
  * @returns a boolean value indicating whether the potentialKey is of type number or not.
1228
1266
  */
1229
- isNodeKey(potentialKey: any): potentialKey is number {
1230
- return typeof potentialKey === 'number';
1267
+ isNotNodeInstance(potentialKey: BTNodeKeyOrNode<K, N>): potentialKey is K {
1268
+ return !(potentialKey instanceof BinaryTreeNode)
1231
1269
  }
1232
1270
 
1233
1271
  dfs<C extends BTNCallback<N>>(
1234
1272
  callback?: C,
1235
1273
  pattern?: DFSOrderPattern,
1236
- beginRoot?: BTNodeKeyOrNode<N>,
1274
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1237
1275
  iterationType?: IterationType,
1238
1276
  includeNull?: false
1239
1277
  ): ReturnType<C>[];
@@ -1241,7 +1279,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1241
1279
  dfs<C extends BTNCallback<N>>(
1242
1280
  callback?: C,
1243
1281
  pattern?: DFSOrderPattern,
1244
- beginRoot?: BTNodeKeyOrNode<N>,
1282
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1245
1283
  iterationType?: IterationType,
1246
1284
  includeNull?: undefined
1247
1285
  ): ReturnType<C>[];
@@ -1249,7 +1287,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1249
1287
  dfs<C extends BTNCallback<N | null | undefined>>(
1250
1288
  callback?: C,
1251
1289
  pattern?: DFSOrderPattern,
1252
- beginRoot?: BTNodeKeyOrNode<N>,
1290
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1253
1291
  iterationType?: IterationType,
1254
1292
  includeNull?: true
1255
1293
  ): ReturnType<C>[];
@@ -1266,7 +1304,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1266
1304
  * `null`, or `undefined`, and returns a value of any type. The default value for this parameter is
1267
1305
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
1268
1306
  * nodes are traversed during the depth-first search. It can have one of the following values:
1269
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1307
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1270
1308
  * for the depth-first search traversal. It can be specified as a key, a node object, or
1271
1309
  * `null`/`undefined`. If not provided, the `beginRoot` will default to the root node of the tree.
1272
1310
  * @param {IterationType} iterationType - The `iterationType` parameter determines the type of
@@ -1280,7 +1318,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1280
1318
  dfs<C extends BTNCallback<N | null | undefined>>(
1281
1319
  callback: C = this._defaultOneParamCallback as C,
1282
1320
  pattern: DFSOrderPattern = 'in',
1283
- beginRoot: BTNodeKeyOrNode<N> = this.root,
1321
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
1284
1322
  iterationType: IterationType = IterationType.ITERATIVE,
1285
1323
  includeNull = false
1286
1324
  ): ReturnType<C>[] {
@@ -1379,21 +1417,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1379
1417
 
1380
1418
  bfs<C extends BTNCallback<N>>(
1381
1419
  callback?: C,
1382
- beginRoot?: BTNodeKeyOrNode<N>,
1420
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1383
1421
  iterationType?: IterationType,
1384
1422
  includeNull?: false
1385
1423
  ): ReturnType<C>[];
1386
1424
 
1387
1425
  bfs<C extends BTNCallback<N>>(
1388
1426
  callback?: C,
1389
- beginRoot?: BTNodeKeyOrNode<N>,
1427
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1390
1428
  iterationType?: IterationType,
1391
1429
  includeNull?: undefined
1392
1430
  ): ReturnType<C>[];
1393
1431
 
1394
1432
  bfs<C extends BTNCallback<N | null | undefined>>(
1395
1433
  callback?: C,
1396
- beginRoot?: BTNodeKeyOrNode<N>,
1434
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1397
1435
  iterationType?: IterationType,
1398
1436
  includeNull?: true
1399
1437
  ): ReturnType<C>[];
@@ -1407,7 +1445,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1407
1445
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1408
1446
  * the breadth-first search traversal. It takes a single parameter, which is the current node being
1409
1447
  * visited, and returns a value of any type.
1410
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1448
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1411
1449
  * starting node for the breadth-first search traversal. It can be specified as a key, a node object,
1412
1450
  * or `null`/`undefined` to indicate the root of the tree. If not provided, the `root` property of
1413
1451
  * the class is used as
@@ -1421,7 +1459,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1421
1459
  */
1422
1460
  bfs<C extends BTNCallback<N | null | undefined>>(
1423
1461
  callback: C = this._defaultOneParamCallback as C,
1424
- beginRoot: BTNodeKeyOrNode<N> = this.root,
1462
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
1425
1463
  iterationType = this.iterationType,
1426
1464
  includeNull = false
1427
1465
  ): ReturnType<C>[] {
@@ -1480,21 +1518,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1480
1518
 
1481
1519
  listLevels<C extends BTNCallback<N>>(
1482
1520
  callback?: C,
1483
- beginRoot?: BTNodeKeyOrNode<N>,
1521
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1484
1522
  iterationType?: IterationType,
1485
1523
  includeNull?: false
1486
1524
  ): ReturnType<C>[][];
1487
1525
 
1488
1526
  listLevels<C extends BTNCallback<N>>(
1489
1527
  callback?: C,
1490
- beginRoot?: BTNodeKeyOrNode<N>,
1528
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1491
1529
  iterationType?: IterationType,
1492
1530
  includeNull?: undefined
1493
1531
  ): ReturnType<C>[][];
1494
1532
 
1495
1533
  listLevels<C extends BTNCallback<N | null | undefined>>(
1496
1534
  callback?: C,
1497
- beginRoot?: BTNodeKeyOrNode<N>,
1535
+ beginRoot?: BTNodeKeyOrNode<K, N>,
1498
1536
  iterationType?: IterationType,
1499
1537
  includeNull?: true
1500
1538
  ): ReturnType<C>[][];
@@ -1509,9 +1547,9 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1509
1547
  * @param {C} callback - The `callback` parameter is a function that will be called for each node in
1510
1548
  * the tree. It takes a single parameter, which can be of type `N`, `null`, or `undefined`, and
1511
1549
  * returns a value of any type.
1512
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1550
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter represents the
1513
1551
  * starting node for traversing the tree. It can be either a node object (`N`), a key value
1514
- * (`BTNKey`), `null`, or `undefined`. If not provided, it defaults to the root node of the tree.
1552
+ * (`K`), `null`, or `undefined`. If not provided, it defaults to the root node of the tree.
1515
1553
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be
1516
1554
  * performed on the tree. It can have two possible values:
1517
1555
  * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
@@ -1522,7 +1560,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1522
1560
  */
1523
1561
  listLevels<C extends BTNCallback<N | null | undefined>>(
1524
1562
  callback: C = this._defaultOneParamCallback as C,
1525
- beginRoot: BTNodeKeyOrNode<N> = this.root,
1563
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root,
1526
1564
  iterationType = this.iterationType,
1527
1565
  includeNull = false
1528
1566
  ): ReturnType<C>[][] {
@@ -1568,26 +1606,24 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1568
1606
  }
1569
1607
 
1570
1608
  /**
1571
- * Time complexity: O(n)
1572
- * Space complexity: O(n)
1609
+ * Time Complexity: O(log n)
1610
+ * Space Complexity: O(1)
1573
1611
  */
1574
1612
 
1575
- getPredecessor(node: N): N;
1576
-
1577
1613
  /**
1578
- * The function `getPredecessor` returns the predecessor node of a given node in a binary tree.
1579
- * @param {BTNKey | N | null | undefined} node - The `node` parameter can be of type `BTNKey`, `N`,
1580
- * `null`, or `undefined`.
1581
- * @returns The function `getPredecessor` returns a value of type `N | undefined`.
1614
+ * Time Complexity: O(log n)
1615
+ * Space Complexity: O(1)
1616
+ *
1617
+ * The function returns the predecessor of a given node in a tree.
1618
+ * @param {N} node - The parameter `node` is of type `RedBlackTreeNode`, which represents a node in a
1619
+ * tree.
1620
+ * @returns the predecessor of the given 'node'.
1582
1621
  */
1583
- getPredecessor(node: BTNodeKeyOrNode<N>): N | undefined {
1584
- node = this.ensureNode(node);
1585
- if (!this.isRealNode(node)) return undefined;
1586
-
1587
- if (node.left) {
1622
+ getPredecessor(node: N): N {
1623
+ if (this.isRealNode(node.left)) {
1588
1624
  let predecessor: N | null | undefined = node.left;
1589
1625
  while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
1590
- if (predecessor) {
1626
+ if (this.isRealNode(predecessor)) {
1591
1627
  predecessor = predecessor.right;
1592
1628
  }
1593
1629
  }
@@ -1599,20 +1635,21 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1599
1635
 
1600
1636
  /**
1601
1637
  * The function `getSuccessor` returns the next node in a binary tree given a current node.
1602
- * @param {BTNKey | N | null} [x] - The parameter `x` can be of type `BTNKey`, `N`, or `null`.
1638
+ * @param {K | N | null} [x] - The parameter `x` can be of type `K`, `N`, or `null`.
1603
1639
  * @returns the successor of the given node or key. The successor is the node that comes immediately
1604
1640
  * after the given node in the inorder traversal of the binary tree.
1605
1641
  */
1606
- getSuccessor(x?: BTNKey | N | null): N | null | undefined {
1642
+ getSuccessor(x?: K | N | null): N | null | undefined {
1643
+
1607
1644
  x = this.ensureNode(x);
1608
- if (!x) return undefined;
1645
+ if (!this.isRealNode(x)) return undefined;
1609
1646
 
1610
- if (x.right) {
1647
+ if (this.isRealNode(x.right)) {
1611
1648
  return this.getLeftMost(x.right);
1612
1649
  }
1613
1650
 
1614
1651
  let y: N | null | undefined = x.parent;
1615
- while (y && y && x === y.right) {
1652
+ while (this.isRealNode(y) && x === y.right) {
1616
1653
  x = y;
1617
1654
  y = y.parent;
1618
1655
  }
@@ -1630,7 +1667,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1630
1667
  * @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
1631
1668
  * determines the order in which the nodes of a binary tree are traversed. It can have one of the
1632
1669
  * following values:
1633
- * @param {BTNKey | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1670
+ * @param {K | N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node
1634
1671
  * for the traversal. It can be specified as a key, a node object, or `null`/`undefined` to indicate
1635
1672
  * the root of the tree. If no value is provided, the default value is the root of the tree.
1636
1673
  * @returns The function `morris` returns an array of values that are the result of invoking the
@@ -1640,7 +1677,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1640
1677
  morris<C extends BTNCallback<N>>(
1641
1678
  callback: C = this._defaultOneParamCallback as C,
1642
1679
  pattern: DFSOrderPattern = 'in',
1643
- beginRoot: BTNodeKeyOrNode<N> = this.root
1680
+ beginRoot: BTNodeKeyOrNode<K, N> = this.root
1644
1681
  ): ReturnType<C>[] {
1645
1682
  beginRoot = this.ensureNode(beginRoot);
1646
1683
  if (beginRoot === null) return [];
@@ -1725,33 +1762,48 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1725
1762
 
1726
1763
  /**
1727
1764
  * Time complexity: O(n)
1728
- * Space complexity: O(1)
1765
+ * Space complexity: O(n)
1729
1766
  */
1730
1767
 
1731
1768
  /**
1732
- * The `forEach` function iterates over each entry in a tree and calls a callback function with the
1733
- * entry and the tree as arguments.
1734
- * @param callback - The callback parameter is a function that will be called for each entry in the
1735
- * tree. It takes two parameters: entry and tree.
1736
- */
1737
- forEach(callback: (entry: [BTNKey, V | undefined], tree: this) => void): void {
1738
- for (const entry of this) {
1739
- callback(entry, this);
1740
- }
1769
+ * Time complexity: O(n)
1770
+ * Space complexity: O(n)
1771
+ *
1772
+ * The `clone` function creates a new tree object and copies all the nodes from the original tree to
1773
+ * the new tree.
1774
+ * @returns The `clone()` method is returning a cloned instance of the `TREE` object.
1775
+ */
1776
+ clone(): TREE {
1777
+ const cloned = this.createTree();
1778
+ this.bfs(node => cloned.add([node.key, node.value]));
1779
+ return cloned;
1741
1780
  }
1742
1781
 
1743
1782
  /**
1744
- * The `filter` function creates a new tree by iterating over the entries of the current tree and
1745
- * adding the entries that satisfy the given predicate.
1746
- * @param predicate - The `predicate` parameter is a function that takes two arguments: `entry` and
1747
- * `tree`.
1748
- * @returns The `filter` method is returning a new tree object that contains only the entries that
1749
- * satisfy the given predicate function.
1783
+ * Time Complexity: O(n)
1784
+ * Space Complexity: O(n)
1750
1785
  */
1751
- filter(predicate: (entry: [BTNKey, V | undefined], tree: this) => boolean) {
1786
+
1787
+ /**
1788
+ * Time Complexity: O(n)
1789
+ * Space Complexity: O(n)
1790
+ *
1791
+ * The `filter` function creates a new tree by iterating over the elements of the current tree and
1792
+ * adding only the elements that satisfy the given predicate function.
1793
+ * @param predicate - The `predicate` parameter is a function that takes three arguments: `value`,
1794
+ * `key`, and `index`. It should return a boolean value indicating whether the pair should be
1795
+ * included in the filtered tree or not.
1796
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value
1797
+ * to be used as the `this` value when executing the `predicate` function. If `thisArg` is provided,
1798
+ * it will be passed as the first argument to the `predicate` function. If `thisArg` is
1799
+ * @returns The `filter` method is returning a new tree object that contains the key-value pairs that
1800
+ * pass the given predicate function.
1801
+ */
1802
+ filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?: any) {
1752
1803
  const newTree = this.createTree();
1804
+ let index = 0;
1753
1805
  for (const [key, value] of this) {
1754
- if (predicate([key, value], this)) {
1806
+ if (predicate.call(thisArg, value, key, index++, this)) {
1755
1807
  newTree.add([key, value]);
1756
1808
  }
1757
1809
  }
@@ -1759,58 +1811,74 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1759
1811
  }
1760
1812
 
1761
1813
  /**
1762
- * The `map` function creates a new tree by applying a callback function to each entry in the current
1763
- * tree.
1764
- * @param callback - The callback parameter is a function that takes two arguments: entry and tree.
1814
+ * Time Complexity: O(n)
1815
+ * Space Complexity: O(n)
1816
+ */
1817
+
1818
+ /**
1819
+ * Time Complexity: O(n)
1820
+ * Space Complexity: O(n)
1821
+ *
1822
+ * The `map` function creates a new tree by applying a callback function to each key-value pair in
1823
+ * the original tree.
1824
+ * @param callback - The callback parameter is a function that will be called for each key-value pair
1825
+ * in the tree. It takes four arguments: the value of the current pair, the key of the current pair,
1826
+ * the index of the current pair, and a reference to the tree itself. The callback function should
1827
+ * return a new
1828
+ * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that allows you to
1829
+ * specify the value of `this` within the callback function. If you pass a value for `thisArg`, it
1830
+ * will be used as the `this` value when the callback function is called. If you don't pass a value
1765
1831
  * @returns The `map` method is returning a new tree object.
1766
1832
  */
1767
- map(callback: (entry: [BTNKey, V | undefined], tree: this) => V) {
1833
+ map(callback: EntryCallback<K, V | undefined, V>, thisArg?: any) {
1768
1834
  const newTree = this.createTree();
1835
+ let index = 0;
1769
1836
  for (const [key, value] of this) {
1770
- newTree.add([key, callback([key, value], this)]);
1837
+ newTree.add([key, callback.call(thisArg, value, key, index++, this)]);
1771
1838
  }
1772
1839
  return newTree;
1773
1840
  }
1774
1841
 
1775
- // TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
1776
- // map<NV>(callback: (entry: [BTNKey, V | undefined], tree: this) => NV) {
1777
- // const newTree = this.createTree();
1778
- // for (const [key, value] of this) {
1779
- // newTree.add(key, callback([key, value], this));
1780
- // }
1781
- // return newTree;
1782
- // }
1783
-
1784
- /**
1785
- * The `reduce` function iterates over the entries of a tree and applies a callback function to each
1786
- * entry, accumulating a single value.
1787
- * @param callback - The callback parameter is a function that takes three arguments: accumulator,
1788
- * entry, and tree. It is called for each entry in the tree and is used to accumulate a single value
1789
- * based on the logic defined in the callback function.
1790
- * @param {T} initialValue - The initialValue parameter is the initial value of the accumulator. It
1791
- * is the value that will be passed as the first argument to the callback function when reducing the
1792
- * elements of the tree.
1793
- * @returns The `reduce` method is returning the final value of the accumulator after iterating over
1794
- * all the entries in the tree and applying the callback function to each entry.
1795
- */
1796
- reduce<T>(callback: (accumulator: T, entry: [BTNKey, V | undefined], tree: this) => T, initialValue: T): T {
1797
- let accumulator = initialValue;
1798
- for (const [key, value] of this) {
1799
- accumulator = callback(accumulator, [key, value], this);
1800
- }
1801
- return accumulator;
1802
- }
1842
+ // // TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
1843
+ // // map<NV>(callback: (entry: [K, V | undefined], tree: this) => NV) {
1844
+ // // const newTree = this.createTree();
1845
+ // // for (const [key, value] of this) {
1846
+ // // newTree.add(key, callback([key, value], this));
1847
+ // // }
1848
+ // // return newTree;
1849
+ // // }
1850
+ //
1803
1851
 
1804
1852
  /**
1805
- * The above function is an iterator for a binary tree that can be used to traverse the tree in
1806
- * either an iterative or recursive manner.
1807
- * @param node - The `node` parameter represents the current node in the binary tree from which the
1808
- * iteration starts. It is an optional parameter with a default value of `this.root`, which means
1809
- * that if no node is provided, the iteration will start from the root of the binary tree.
1810
- * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
1811
- * binary tree nodes in a specific order.
1853
+ * The `print` function is used to display a binary tree structure in a visually appealing way.
1854
+ * @param {K | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `K | N | null |
1855
+ * undefined`. It represents the root node of a binary tree. The root node can have one of the
1856
+ * following types:
1857
+ * @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.
1812
1858
  */
1813
- * [Symbol.iterator](node = this.root): Generator<[BTNKey, V | undefined], void, undefined> {
1859
+ print(beginRoot: BTNodeKeyOrNode<K, N> = this.root, options?: BinaryTreePrintOptions): void {
1860
+ const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1861
+ beginRoot = this.ensureNode(beginRoot);
1862
+ if (!beginRoot) return;
1863
+
1864
+ if (opts.isShowUndefined) console.log(`U for undefined
1865
+ `);
1866
+ if (opts.isShowNull) console.log(`N for null
1867
+ `);
1868
+ if (opts.isShowRedBlackNIL) console.log(`S for Sentinel Node
1869
+ `);
1870
+
1871
+ const display = (root: N | null | undefined): void => {
1872
+ const [lines, , ,] = this._displayAux(root, opts);
1873
+ for (const line of lines) {
1874
+ console.log(line);
1875
+ }
1876
+ };
1877
+
1878
+ display(beginRoot);
1879
+ }
1880
+
1881
+ protected* _getIterator(node = this.root): IterableIterator<[K, V | undefined]> {
1814
1882
  if (!node) return;
1815
1883
 
1816
1884
  if (this.iterationType === IterationType.ITERATIVE) {
@@ -1818,58 +1886,29 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1818
1886
  let current: N | null | undefined = node;
1819
1887
 
1820
1888
  while (current || stack.length > 0) {
1821
- while (current && !isNaN(current.key)) {
1889
+ while (current && !isNaN(this.extractor(current.key))) {
1822
1890
  stack.push(current);
1823
1891
  current = current.left;
1824
1892
  }
1825
1893
 
1826
1894
  current = stack.pop();
1827
1895
 
1828
- if (current && !isNaN(current.key)) {
1896
+ if (current && !isNaN(this.extractor(current.key))) {
1829
1897
  yield [current.key, current.value];
1830
1898
  current = current.right;
1831
1899
  }
1832
1900
  }
1833
1901
  } else {
1834
- if (node.left && !isNaN(node.key)) {
1902
+ if (node.left && !isNaN(this.extractor(node.key))) {
1835
1903
  yield* this[Symbol.iterator](node.left);
1836
1904
  }
1837
1905
  yield [node.key, node.value];
1838
- if (node.right && !isNaN(node.key)) {
1906
+ if (node.right && !isNaN(this.extractor(node.key))) {
1839
1907
  yield* this[Symbol.iterator](node.right);
1840
1908
  }
1841
1909
  }
1842
1910
  }
1843
1911
 
1844
- /**
1845
- * The `print` function is used to display a binary tree structure in a visually appealing way.
1846
- * @param {BTNKey | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `BTNKey | N | null |
1847
- * undefined`. It represents the root node of a binary tree. The root node can have one of the
1848
- * following types:
1849
- * @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.
1850
- */
1851
- print(beginRoot: BTNodeKeyOrNode<N> = this.root, options?: BinaryTreePrintOptions): void {
1852
- const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1853
- beginRoot = this.ensureNode(beginRoot);
1854
- if (!beginRoot) return;
1855
-
1856
- if (opts.isShowUndefined) console.log(`U for undefined
1857
- `);
1858
- if (opts.isShowNull) console.log(`N for null
1859
- `);
1860
- if (opts.isShowRedBlackNIL) console.log(`S for Sentinel Node
1861
- `);
1862
-
1863
- const display = (root: N | null | undefined): void => {
1864
- const [lines, , ,] = this._displayAux(root, opts);
1865
- for (const line of lines) {
1866
- console.log(line);
1867
- }
1868
- };
1869
-
1870
- display(beginRoot);
1871
- }
1872
-
1873
1912
  protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
1874
1913
  const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
1875
1914
  const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
@@ -1879,12 +1918,13 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1879
1918
  return emptyDisplayLayout;
1880
1919
  } else if (node === undefined && !isShowUndefined) {
1881
1920
  return emptyDisplayLayout;
1882
- } else if (node !== null && node !== undefined && isNaN(node.key) && !isShowRedBlackNIL) {
1921
+ } else if (node !== null && node !== undefined && isNaN(this.extractor(node.key)) && !isShowRedBlackNIL) {
1883
1922
  return emptyDisplayLayout;
1884
1923
  } else if (node !== null && node !== undefined) {
1885
1924
  // Display logic of normal nodes
1886
1925
 
1887
- const key = node.key, line = isNaN(key) ? 'S' : key.toString(), width = line.length;
1926
+ const key = node.key, line = isNaN(this.extractor(key)) ? 'S' : this.extractor(key).toString(),
1927
+ width = line.length;
1888
1928
 
1889
1929
  return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options))
1890
1930
 
@@ -1928,7 +1968,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1928
1968
  * @param {N} destNode - The destination node to swap.
1929
1969
  * @returns {N} - The destination node after the swap.
1930
1970
  */
1931
- protected _swapProperties(srcNode: BTNodeKeyOrNode<N>, destNode: BTNodeKeyOrNode<N>): N | undefined {
1971
+ protected _swapProperties(srcNode: BTNodeKeyOrNode<K, N>, destNode: BTNodeKeyOrNode<K, N>): N | undefined {
1932
1972
  srcNode = this.ensureNode(srcNode);
1933
1973
  destNode = this.ensureNode(destNode);
1934
1974
 
@@ -1986,8 +2026,8 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1986
2026
  * the binary tree. If neither the left nor right child is available, the function returns undefined.
1987
2027
  * If the parent node is null, the function also returns undefined.
1988
2028
  */
1989
- protected _addTo(newNode: N | null | undefined, parent: BTNodeKeyOrNode<N>): N | null | undefined {
1990
- if (this.isNodeKey(parent)) parent = this.getNode(parent);
2029
+ protected _addTo(newNode: N | null | undefined, parent: BTNodeKeyOrNode<K, N>): N | null | undefined {
2030
+ if (this.isNotNodeInstance(parent)) parent = this.getNode(parent);
1991
2031
 
1992
2032
  if (parent) {
1993
2033
  // When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.