data-structure-typed 1.42.5 → 1.42.7
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.
- package/CHANGELOG.md +1 -1
- package/CONTRIBUTING.md +66 -5
- package/README.md +218 -126
- package/benchmark/report.html +12 -12
- package/benchmark/report.json +101 -101
- package/dist/cjs/src/data-structures/binary-tree/avl-tree.d.ts +5 -5
- package/dist/cjs/src/data-structures/binary-tree/avl-tree.js +19 -14
- package/dist/cjs/src/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/cjs/src/data-structures/binary-tree/binary-tree.d.ts +108 -60
- package/dist/cjs/src/data-structures/binary-tree/binary-tree.js +189 -89
- package/dist/cjs/src/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/src/data-structures/binary-tree/bst.d.ts +30 -8
- package/dist/cjs/src/data-structures/binary-tree/bst.js +77 -28
- package/dist/cjs/src/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/cjs/src/data-structures/binary-tree/rb-tree.d.ts +35 -28
- package/dist/cjs/src/data-structures/binary-tree/rb-tree.js +44 -45
- package/dist/cjs/src/data-structures/binary-tree/rb-tree.js.map +1 -1
- package/dist/cjs/src/data-structures/binary-tree/tree-multimap.d.ts +7 -12
- package/dist/cjs/src/data-structures/binary-tree/tree-multimap.js +38 -37
- package/dist/cjs/src/data-structures/binary-tree/tree-multimap.js.map +1 -1
- package/dist/cjs/src/interfaces/binary-tree.d.ts +2 -2
- package/dist/cjs/src/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
- package/dist/cjs/src/types/data-structures/binary-tree/binary-tree.js +6 -0
- package/dist/cjs/src/types/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/src/types/data-structures/binary-tree/rb-tree.d.ts +2 -2
- package/dist/mjs/src/data-structures/binary-tree/avl-tree.d.ts +5 -5
- package/dist/mjs/src/data-structures/binary-tree/avl-tree.js +19 -14
- package/dist/mjs/src/data-structures/binary-tree/binary-tree.d.ts +108 -60
- package/dist/mjs/src/data-structures/binary-tree/binary-tree.js +191 -89
- package/dist/mjs/src/data-structures/binary-tree/bst.d.ts +30 -8
- package/dist/mjs/src/data-structures/binary-tree/bst.js +78 -27
- package/dist/mjs/src/data-structures/binary-tree/rb-tree.d.ts +35 -28
- package/dist/mjs/src/data-structures/binary-tree/rb-tree.js +43 -45
- package/dist/mjs/src/data-structures/binary-tree/tree-multimap.d.ts +7 -12
- package/dist/mjs/src/data-structures/binary-tree/tree-multimap.js +38 -37
- package/dist/mjs/src/interfaces/binary-tree.d.ts +2 -2
- package/dist/mjs/src/types/data-structures/binary-tree/binary-tree.d.ts +1 -1
- package/dist/mjs/src/types/data-structures/binary-tree/binary-tree.js +6 -0
- package/dist/mjs/src/types/data-structures/binary-tree/rb-tree.d.ts +2 -2
- package/dist/umd/data-structure-typed.min.js +1 -1
- package/dist/umd/data-structure-typed.min.js.map +1 -1
- package/package.json +5 -5
- package/src/data-structures/binary-tree/avl-tree.ts +24 -18
- package/src/data-structures/binary-tree/binary-tree.ts +248 -142
- package/src/data-structures/binary-tree/bst.ts +88 -38
- package/src/data-structures/binary-tree/rb-tree.ts +52 -58
- package/src/data-structures/binary-tree/tree-multimap.ts +50 -54
- package/src/interfaces/binary-tree.ts +2 -2
- package/src/types/data-structures/binary-tree/binary-tree.ts +7 -1
- package/src/types/data-structures/binary-tree/rb-tree.ts +2 -2
- package/test/performance/reportor.ts +2 -2
- package/test/unit/data-structures/binary-tree/rb-tree.test.ts +9 -9
|
@@ -102,19 +102,20 @@ class BinaryTree {
|
|
|
102
102
|
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
|
|
103
103
|
*/
|
|
104
104
|
constructor(options) {
|
|
105
|
-
if (options
|
|
105
|
+
if (options) {
|
|
106
106
|
const { iterationType = types_1.IterationType.ITERATIVE } = options;
|
|
107
107
|
this.iterationType = iterationType;
|
|
108
108
|
}
|
|
109
|
+
this._size = 0;
|
|
109
110
|
}
|
|
110
|
-
_root
|
|
111
|
+
_root;
|
|
111
112
|
/**
|
|
112
113
|
* Get the root node of the binary tree.
|
|
113
114
|
*/
|
|
114
115
|
get root() {
|
|
115
116
|
return this._root;
|
|
116
117
|
}
|
|
117
|
-
_size
|
|
118
|
+
_size;
|
|
118
119
|
/**
|
|
119
120
|
* Get the number of nodes in the binary tree.
|
|
120
121
|
*/
|
|
@@ -130,20 +131,6 @@ class BinaryTree {
|
|
|
130
131
|
createNode(key, value) {
|
|
131
132
|
return new BinaryTreeNode(key, value);
|
|
132
133
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Clear the binary tree, removing all nodes.
|
|
135
|
-
*/
|
|
136
|
-
clear() {
|
|
137
|
-
this._setRoot(undefined);
|
|
138
|
-
this._size = 0;
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Check if the binary tree is empty.
|
|
142
|
-
* @returns {boolean} - True if the binary tree is empty, false otherwise.
|
|
143
|
-
*/
|
|
144
|
-
isEmpty() {
|
|
145
|
-
return this.size === 0;
|
|
146
|
-
}
|
|
147
134
|
/**
|
|
148
135
|
* Add a node with the given key and value to the binary tree.
|
|
149
136
|
* @param {BTNKey | N | null} keyOrNode - The key or node to add to the binary tree.
|
|
@@ -177,7 +164,7 @@ class BinaryTree {
|
|
|
177
164
|
if (keyOrNode === null) {
|
|
178
165
|
needInsert = null;
|
|
179
166
|
}
|
|
180
|
-
else if (
|
|
167
|
+
else if (this.isNodeKey(keyOrNode)) {
|
|
181
168
|
needInsert = this.createNode(keyOrNode, value);
|
|
182
169
|
}
|
|
183
170
|
else if (keyOrNode instanceof BinaryTreeNode) {
|
|
@@ -186,19 +173,12 @@ class BinaryTree {
|
|
|
186
173
|
else {
|
|
187
174
|
return;
|
|
188
175
|
}
|
|
189
|
-
// const key = typeof keyOrNode === 'number' ? keyOrNode : keyOrNode ? keyOrNode.key : undefined;
|
|
190
|
-
// const existNode = key !== undefined ? this.getNode(key, (node: N) => node.key) : undefined;
|
|
191
176
|
if (this.root) {
|
|
192
|
-
// if (existNode) {
|
|
193
|
-
// existNode.value = value;
|
|
194
|
-
// inserted = existNode;
|
|
195
|
-
// } else {
|
|
196
177
|
inserted = _bfs(this.root, needInsert);
|
|
197
|
-
// }
|
|
198
178
|
}
|
|
199
179
|
else {
|
|
200
180
|
this._setRoot(needInsert);
|
|
201
|
-
if (needInsert
|
|
181
|
+
if (needInsert) {
|
|
202
182
|
this._size = 1;
|
|
203
183
|
}
|
|
204
184
|
else {
|
|
@@ -235,40 +215,41 @@ class BinaryTree {
|
|
|
235
215
|
* The `refill` function clears the binary tree and adds multiple nodes with the given IDs or nodes and optional data.
|
|
236
216
|
* @param {(BTNKey | N)[]} keysOrNodes - The `keysOrNodes` parameter is an array that can contain either
|
|
237
217
|
* `BTNKey` or `N` values.
|
|
238
|
-
* @param {N[] | Array<V>} [
|
|
218
|
+
* @param {N[] | Array<V>} [values] - The `data` parameter is an optional array of values that will be assigned to
|
|
239
219
|
* the nodes being added. If provided, the length of the `data` array should be equal to the length of the `keysOrNodes`
|
|
240
220
|
* array. Each value in the `data` array will be assigned to the
|
|
241
221
|
* @returns The method is returning a boolean value.
|
|
242
222
|
*/
|
|
243
|
-
refill(keysOrNodes,
|
|
223
|
+
refill(keysOrNodes, values) {
|
|
244
224
|
this.clear();
|
|
245
|
-
return keysOrNodes.length === this.addMany(keysOrNodes,
|
|
225
|
+
return keysOrNodes.length === this.addMany(keysOrNodes, values).length;
|
|
246
226
|
}
|
|
247
227
|
/**
|
|
248
228
|
* The `delete` function removes a node from a binary search tree and returns the deleted node along
|
|
249
229
|
* with the parent node that needs to be balanced.
|
|
250
230
|
* a key (`BTNKey`). If it is a key, the function will find the corresponding node in the
|
|
251
231
|
* binary tree.
|
|
252
|
-
* @returns an array of `
|
|
232
|
+
* @returns an array of `BiTreeDeleteResult<N>` objects.
|
|
253
233
|
* @param {ReturnType<C>} identifier - The `identifier` parameter is either a
|
|
254
234
|
* `BTNKey` or a generic type `N`. It represents the property of the node that we are
|
|
255
235
|
* searching for. It can be a specific key value or any other property of the node.
|
|
256
236
|
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
|
|
257
237
|
* value. This value is compared with the `identifier` parameter to determine if the node should be
|
|
258
238
|
* included in the result. The `callback` parameter has a default value of
|
|
259
|
-
* `this.
|
|
239
|
+
* `this._defaultOneParamCallback`, which
|
|
260
240
|
*/
|
|
261
|
-
delete(identifier, callback = this.
|
|
262
|
-
const
|
|
241
|
+
delete(identifier, callback = this._defaultOneParamCallback) {
|
|
242
|
+
const deletedResult = [];
|
|
263
243
|
if (!this.root)
|
|
264
|
-
return
|
|
244
|
+
return deletedResult;
|
|
265
245
|
if (identifier instanceof BinaryTreeNode)
|
|
266
246
|
callback = (node => node);
|
|
267
247
|
const curr = this.getNode(identifier, callback);
|
|
268
248
|
if (!curr)
|
|
269
|
-
return
|
|
249
|
+
return deletedResult;
|
|
270
250
|
const parent = curr?.parent ? curr.parent : null;
|
|
271
|
-
let needBalanced =
|
|
251
|
+
let needBalanced = undefined;
|
|
252
|
+
let orgCurrent = curr;
|
|
272
253
|
if (!curr.left) {
|
|
273
254
|
if (!parent) {
|
|
274
255
|
// Handle the case when there's only one root node
|
|
@@ -300,8 +281,8 @@ class BinaryTree {
|
|
|
300
281
|
}
|
|
301
282
|
}
|
|
302
283
|
this._size = this.size - 1;
|
|
303
|
-
|
|
304
|
-
return
|
|
284
|
+
deletedResult.push({ deleted: orgCurrent, needBalanced });
|
|
285
|
+
return deletedResult;
|
|
305
286
|
}
|
|
306
287
|
/**
|
|
307
288
|
* The function `getDepth` calculates the depth of a given node in a binary tree relative to a
|
|
@@ -316,10 +297,8 @@ class BinaryTree {
|
|
|
316
297
|
* @returns the depth of the `distNode` relative to the `beginRoot`.
|
|
317
298
|
*/
|
|
318
299
|
getDepth(distNode, beginRoot = this.root) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (typeof beginRoot === 'number')
|
|
322
|
-
beginRoot = this.getNode(beginRoot);
|
|
300
|
+
distNode = this.ensureNotKey(distNode);
|
|
301
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
323
302
|
let depth = 0;
|
|
324
303
|
while (distNode?.parent) {
|
|
325
304
|
if (distNode === beginRoot) {
|
|
@@ -343,8 +322,7 @@ class BinaryTree {
|
|
|
343
322
|
* @returns the height of the binary tree.
|
|
344
323
|
*/
|
|
345
324
|
getHeight(beginRoot = this.root, iterationType = this.iterationType) {
|
|
346
|
-
|
|
347
|
-
beginRoot = this.getNode(beginRoot);
|
|
325
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
348
326
|
if (!beginRoot)
|
|
349
327
|
return -1;
|
|
350
328
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
@@ -365,12 +343,10 @@ class BinaryTree {
|
|
|
365
343
|
let maxHeight = 0;
|
|
366
344
|
while (stack.length > 0) {
|
|
367
345
|
const { node, depth } = stack.pop();
|
|
368
|
-
if (node.left)
|
|
346
|
+
if (node.left)
|
|
369
347
|
stack.push({ node: node.left, depth: depth + 1 });
|
|
370
|
-
|
|
371
|
-
if (node.right) {
|
|
348
|
+
if (node.right)
|
|
372
349
|
stack.push({ node: node.right, depth: depth + 1 });
|
|
373
|
-
}
|
|
374
350
|
maxHeight = Math.max(maxHeight, depth);
|
|
375
351
|
}
|
|
376
352
|
return maxHeight;
|
|
@@ -387,6 +363,7 @@ class BinaryTree {
|
|
|
387
363
|
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
|
|
388
364
|
*/
|
|
389
365
|
getMinHeight(beginRoot = this.root, iterationType = this.iterationType) {
|
|
366
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
390
367
|
if (!beginRoot)
|
|
391
368
|
return -1;
|
|
392
369
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
@@ -448,7 +425,7 @@ class BinaryTree {
|
|
|
448
425
|
* @param callback - The `callback` parameter is a function that takes a node as input and returns a
|
|
449
426
|
* value. This value is compared with the `identifier` parameter to determine if the node should be
|
|
450
427
|
* included in the result. The `callback` parameter has a default value of
|
|
451
|
-
* `this.
|
|
428
|
+
* `this._defaultOneParamCallback`, which
|
|
452
429
|
* @param [onlyOne=false] - A boolean value indicating whether to stop searching after finding the
|
|
453
430
|
* first node that matches the identifier. If set to true, the function will return an array with
|
|
454
431
|
* only one element (or an empty array if no matching node is found). If set to false (default), the
|
|
@@ -460,11 +437,14 @@ class BinaryTree {
|
|
|
460
437
|
* traverse the binary tree. It can have two possible values:
|
|
461
438
|
* @returns The function `getNodes` returns an array of nodes (`N[]`).
|
|
462
439
|
*/
|
|
463
|
-
getNodes(identifier, callback = this.
|
|
440
|
+
getNodes(identifier, callback = this._defaultOneParamCallback, onlyOne = false, beginRoot = this.root, iterationType = this.iterationType) {
|
|
464
441
|
if (!beginRoot)
|
|
465
442
|
return [];
|
|
466
443
|
if (identifier instanceof BinaryTreeNode)
|
|
467
444
|
callback = (node => node);
|
|
445
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
446
|
+
if (!beginRoot)
|
|
447
|
+
return [];
|
|
468
448
|
const ans = [];
|
|
469
449
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
470
450
|
const _traverse = (cur) => {
|
|
@@ -505,7 +485,7 @@ class BinaryTree {
|
|
|
505
485
|
* @param callback - The `callback` parameter is a function that is used to determine whether a node
|
|
506
486
|
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
|
|
507
487
|
* whether the node matches the criteria or not. The default callback function
|
|
508
|
-
* `this.
|
|
488
|
+
* `this._defaultOneParamCallback` is used if no callback function is
|
|
509
489
|
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
|
|
510
490
|
* the node from which the search should begin. By default, it is set to `this.root`, which means the
|
|
511
491
|
* search will start from the root node of the binary tree. However, you can provide a different node
|
|
@@ -514,7 +494,7 @@ class BinaryTree {
|
|
|
514
494
|
* performed when searching for nodes in the binary tree. It can have one of the following values:
|
|
515
495
|
* @returns a boolean value.
|
|
516
496
|
*/
|
|
517
|
-
has(identifier, callback = this.
|
|
497
|
+
has(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
518
498
|
if (identifier instanceof BinaryTreeNode)
|
|
519
499
|
callback = (node => node);
|
|
520
500
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
|
|
@@ -527,18 +507,72 @@ class BinaryTree {
|
|
|
527
507
|
* @param callback - The `callback` parameter is a function that is used to determine whether a node
|
|
528
508
|
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
|
|
529
509
|
* whether the node matches the criteria or not. The default callback function
|
|
530
|
-
* (`this.
|
|
510
|
+
* (`this._defaultOneParamCallback`) is used if no callback function is
|
|
531
511
|
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
|
|
532
512
|
* the root node from which the search should begin.
|
|
533
513
|
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
|
|
534
514
|
* performed when searching for a node in the binary tree. It can have one of the following values:
|
|
535
515
|
* @returns either the found node (of type N) or null if no node is found.
|
|
536
516
|
*/
|
|
537
|
-
getNode(identifier, callback = this.
|
|
517
|
+
getNode(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
538
518
|
if (identifier instanceof BinaryTreeNode)
|
|
539
519
|
callback = (node => node);
|
|
540
520
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
|
|
541
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* The function `getNodeByKey` searches for a node in a binary tree by its key, using either
|
|
524
|
+
* recursive or iterative iteration.
|
|
525
|
+
* @param {BTNKey} key - The `key` parameter is the key value that we are searching for in the tree.
|
|
526
|
+
* It is used to find the node with the matching key value.
|
|
527
|
+
* @param iterationType - The `iterationType` parameter is used to determine whether the search for
|
|
528
|
+
* the node with the given key should be performed iteratively or recursively. It has two possible
|
|
529
|
+
* values:
|
|
530
|
+
* @returns The function `getNodeByKey` returns a node (`N`) if a node with the specified key is
|
|
531
|
+
* found in the binary tree. If no node is found, it returns `undefined`.
|
|
532
|
+
*/
|
|
533
|
+
getNodeByKey(key, iterationType = types_1.IterationType.ITERATIVE) {
|
|
534
|
+
if (!this.root)
|
|
535
|
+
return undefined;
|
|
536
|
+
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
537
|
+
const _dfs = (cur) => {
|
|
538
|
+
if (cur.key === key)
|
|
539
|
+
return cur;
|
|
540
|
+
if (!cur.left && !cur.right)
|
|
541
|
+
return;
|
|
542
|
+
if (cur.left)
|
|
543
|
+
return _dfs(cur.left);
|
|
544
|
+
if (cur.right)
|
|
545
|
+
return _dfs(cur.right);
|
|
546
|
+
};
|
|
547
|
+
return _dfs(this.root);
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
const queue = new queue_1.Queue([this.root]);
|
|
551
|
+
while (queue.size > 0) {
|
|
552
|
+
const cur = queue.shift();
|
|
553
|
+
if (cur) {
|
|
554
|
+
if (cur.key === key)
|
|
555
|
+
return cur;
|
|
556
|
+
cur.left && queue.push(cur.left);
|
|
557
|
+
cur.right && queue.push(cur.right);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* The function `ensureNotKey` returns the node corresponding to the given key if it is a valid node
|
|
564
|
+
* key, otherwise it returns the key itself.
|
|
565
|
+
* @param {BTNKey | N | null | undefined} key - The `key` parameter can be of type `BTNKey`, `N`,
|
|
566
|
+
* `null`, or `undefined`. It represents a key used to identify a node in a binary tree.
|
|
567
|
+
* @param iterationType - The `iterationType` parameter is an optional parameter that specifies the
|
|
568
|
+
* type of iteration to be used when searching for a node by key. It has a default value of
|
|
569
|
+
* `IterationType.ITERATIVE`.
|
|
570
|
+
* @returns either the node corresponding to the given key if it is a valid node key, or the key
|
|
571
|
+
* itself if it is not a valid node key.
|
|
572
|
+
*/
|
|
573
|
+
ensureNotKey(key, iterationType = types_1.IterationType.ITERATIVE) {
|
|
574
|
+
return this.isNodeKey(key) ? this.getNodeByKey(key, iterationType) : key;
|
|
575
|
+
}
|
|
542
576
|
/**
|
|
543
577
|
* The function `get` returns the first node value in a binary tree that matches the given property or key.
|
|
544
578
|
* @param {BTNKey | N} identifier - The `identifier` parameter is the key or value of
|
|
@@ -547,18 +581,32 @@ class BinaryTree {
|
|
|
547
581
|
* @param callback - The `callback` parameter is a function that is used to determine whether a node
|
|
548
582
|
* matches the desired criteria. It takes a node as input and returns a boolean value indicating
|
|
549
583
|
* whether the node matches the criteria or not. The default callback function
|
|
550
|
-
* (`this.
|
|
584
|
+
* (`this._defaultOneParamCallback`) is used if no callback function is
|
|
551
585
|
* @param beginRoot - The `beginRoot` parameter is the starting point for the search. It specifies
|
|
552
586
|
* the root node from which the search should begin.
|
|
553
587
|
* @param iterationType - The `iterationType` parameter specifies the type of iteration to be
|
|
554
588
|
* performed when searching for a node in the binary tree. It can have one of the following values:
|
|
555
589
|
* @returns either the found value (of type V) or undefined if no node value is found.
|
|
556
590
|
*/
|
|
557
|
-
get(identifier, callback = this.
|
|
591
|
+
get(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
558
592
|
if (identifier instanceof BinaryTreeNode)
|
|
559
593
|
callback = (node => node);
|
|
560
594
|
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
|
|
561
595
|
}
|
|
596
|
+
/**
|
|
597
|
+
* Clear the binary tree, removing all nodes.
|
|
598
|
+
*/
|
|
599
|
+
clear() {
|
|
600
|
+
this._setRoot(undefined);
|
|
601
|
+
this._size = 0;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Check if the binary tree is empty.
|
|
605
|
+
* @returns {boolean} - True if the binary tree is empty, false otherwise.
|
|
606
|
+
*/
|
|
607
|
+
isEmpty() {
|
|
608
|
+
return this.size === 0;
|
|
609
|
+
}
|
|
562
610
|
/**
|
|
563
611
|
* The function `getPathToRoot` returns an array of nodes starting from a given node and traversing
|
|
564
612
|
* up to the root node, with the option to reverse the order of the nodes.
|
|
@@ -572,6 +620,9 @@ class BinaryTree {
|
|
|
572
620
|
getPathToRoot(beginRoot, isReverse = true) {
|
|
573
621
|
// TODO to support get path through passing key
|
|
574
622
|
const result = [];
|
|
623
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
624
|
+
if (!beginRoot)
|
|
625
|
+
return result;
|
|
575
626
|
while (beginRoot.parent) {
|
|
576
627
|
// Array.push + Array.reverse is more efficient than Array.unshift
|
|
577
628
|
// TODO may consider using Deque, so far this is not the performance bottleneck
|
|
@@ -593,13 +644,12 @@ class BinaryTree {
|
|
|
593
644
|
* no leftmost node, it returns `null`.
|
|
594
645
|
*/
|
|
595
646
|
getLeftMost(beginRoot = this.root, iterationType = this.iterationType) {
|
|
596
|
-
|
|
597
|
-
beginRoot = this.getNode(beginRoot);
|
|
647
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
598
648
|
if (!beginRoot)
|
|
599
649
|
return beginRoot;
|
|
600
650
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
601
651
|
const _traverse = (cur) => {
|
|
602
|
-
if (!cur.left)
|
|
652
|
+
if (!this.isRealNode(cur.left))
|
|
603
653
|
return cur;
|
|
604
654
|
return _traverse(cur.left);
|
|
605
655
|
};
|
|
@@ -608,7 +658,7 @@ class BinaryTree {
|
|
|
608
658
|
else {
|
|
609
659
|
// Indirect implementation of iteration using tail recursion optimization
|
|
610
660
|
const _traverse = (0, utils_1.trampoline)((cur) => {
|
|
611
|
-
if (!cur.left)
|
|
661
|
+
if (!this.isRealNode(cur.left))
|
|
612
662
|
return cur;
|
|
613
663
|
return _traverse.cont(cur.left);
|
|
614
664
|
});
|
|
@@ -628,11 +678,12 @@ class BinaryTree {
|
|
|
628
678
|
*/
|
|
629
679
|
getRightMost(beginRoot = this.root, iterationType = this.iterationType) {
|
|
630
680
|
// TODO support get right most by passing key in
|
|
681
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
631
682
|
if (!beginRoot)
|
|
632
683
|
return beginRoot;
|
|
633
684
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
634
685
|
const _traverse = (cur) => {
|
|
635
|
-
if (!cur.right)
|
|
686
|
+
if (!this.isRealNode(cur.right))
|
|
636
687
|
return cur;
|
|
637
688
|
return _traverse(cur.right);
|
|
638
689
|
};
|
|
@@ -641,7 +692,7 @@ class BinaryTree {
|
|
|
641
692
|
else {
|
|
642
693
|
// Indirect implementation of iteration using tail recursion optimization
|
|
643
694
|
const _traverse = (0, utils_1.trampoline)((cur) => {
|
|
644
|
-
if (!cur.right)
|
|
695
|
+
if (!this.isRealNode(cur.right))
|
|
645
696
|
return cur;
|
|
646
697
|
return _traverse.cont(cur.right);
|
|
647
698
|
});
|
|
@@ -659,6 +710,7 @@ class BinaryTree {
|
|
|
659
710
|
*/
|
|
660
711
|
isSubtreeBST(beginRoot, iterationType = this.iterationType) {
|
|
661
712
|
// TODO there is a bug
|
|
713
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
662
714
|
if (!beginRoot)
|
|
663
715
|
return true;
|
|
664
716
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
@@ -716,9 +768,8 @@ class BinaryTree {
|
|
|
716
768
|
* @param includeNull - The choice to output null values during binary tree traversal should be provided.
|
|
717
769
|
* @returns The function `subTreeTraverse` returns an array of `ReturnType<BTNCallback<N>>`.
|
|
718
770
|
*/
|
|
719
|
-
subTreeTraverse(callback = this.
|
|
720
|
-
|
|
721
|
-
beginRoot = this.getNode(beginRoot);
|
|
771
|
+
subTreeTraverse(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
772
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
722
773
|
const ans = [];
|
|
723
774
|
if (!beginRoot)
|
|
724
775
|
return ans;
|
|
@@ -757,21 +808,46 @@ class BinaryTree {
|
|
|
757
808
|
}
|
|
758
809
|
return ans;
|
|
759
810
|
}
|
|
760
|
-
|
|
811
|
+
/**
|
|
812
|
+
* The function checks if a given node is a real node by verifying if it is an instance of
|
|
813
|
+
* BinaryTreeNode and its key is not NaN.
|
|
814
|
+
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
|
|
815
|
+
* @returns a boolean value.
|
|
816
|
+
*/
|
|
817
|
+
isRealNode(node) {
|
|
761
818
|
return node instanceof BinaryTreeNode && node.key.toString() !== 'NaN';
|
|
762
819
|
}
|
|
820
|
+
/**
|
|
821
|
+
* The function checks if a given node is a BinaryTreeNode instance and has a key value of NaN.
|
|
822
|
+
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
|
|
823
|
+
* @returns a boolean value.
|
|
824
|
+
*/
|
|
763
825
|
isNIL(node) {
|
|
764
826
|
return node instanceof BinaryTreeNode && node.key.toString() === 'NaN';
|
|
765
827
|
}
|
|
828
|
+
/**
|
|
829
|
+
* The function checks if a given node is a real node or null.
|
|
830
|
+
* @param {any} node - The parameter `node` is of type `any`, which means it can be any data type.
|
|
831
|
+
* @returns a boolean value.
|
|
832
|
+
*/
|
|
766
833
|
isNodeOrNull(node) {
|
|
767
|
-
return this.
|
|
834
|
+
return this.isRealNode(node) || node === null;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* The function "isNodeKey" checks if a potential key is a number.
|
|
838
|
+
* @param {any} potentialKey - The potentialKey parameter is of type any, which means it can be any
|
|
839
|
+
* data type.
|
|
840
|
+
* @returns a boolean value indicating whether the potentialKey is of type number or not.
|
|
841
|
+
*/
|
|
842
|
+
isNodeKey(potentialKey) {
|
|
843
|
+
return typeof potentialKey === 'number';
|
|
768
844
|
}
|
|
769
845
|
/**
|
|
770
846
|
* The `dfs` function performs a depth-first search traversal on a binary tree, executing a callback
|
|
771
847
|
* function on each node according to a specified order pattern.
|
|
772
848
|
* @param callback - The `callback` parameter is a function that will be called on each node during
|
|
773
849
|
* the depth-first search traversal. It takes a node as input and returns a value. The default value
|
|
774
|
-
* is `this.
|
|
850
|
+
* is `this._defaultOneParamCallback`, which is a callback function defined elsewhere in the code.
|
|
775
851
|
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter determines the order in which the
|
|
776
852
|
* nodes are visited during the depth-first search. There are three possible values for `pattern`:
|
|
777
853
|
* @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the depth-first
|
|
@@ -782,7 +858,8 @@ class BinaryTree {
|
|
|
782
858
|
* @param includeNull - The choice to output null values during binary tree traversal should be provided.
|
|
783
859
|
* @returns The function `dfs` returns an array of `ReturnType<BTNCallback<N>>` values.
|
|
784
860
|
*/
|
|
785
|
-
dfs(callback = this.
|
|
861
|
+
dfs(callback = this._defaultOneParamCallback, pattern = 'in', beginRoot = this.root, iterationType = types_1.IterationType.ITERATIVE, includeNull = false) {
|
|
862
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
786
863
|
if (!beginRoot)
|
|
787
864
|
return [];
|
|
788
865
|
const ans = [];
|
|
@@ -800,7 +877,7 @@ class BinaryTree {
|
|
|
800
877
|
else {
|
|
801
878
|
if (node && node.left)
|
|
802
879
|
_traverse(node.left);
|
|
803
|
-
this.
|
|
880
|
+
this.isRealNode(node) && ans.push(callback(node));
|
|
804
881
|
if (node && node.right)
|
|
805
882
|
_traverse(node.right);
|
|
806
883
|
}
|
|
@@ -814,7 +891,7 @@ class BinaryTree {
|
|
|
814
891
|
_traverse(node.right);
|
|
815
892
|
}
|
|
816
893
|
else {
|
|
817
|
-
this.
|
|
894
|
+
this.isRealNode(node) && ans.push(callback(node));
|
|
818
895
|
if (node && node.left)
|
|
819
896
|
_traverse(node.left);
|
|
820
897
|
if (node && node.right)
|
|
@@ -834,7 +911,7 @@ class BinaryTree {
|
|
|
834
911
|
_traverse(node.left);
|
|
835
912
|
if (node && node.right)
|
|
836
913
|
_traverse(node.right);
|
|
837
|
-
this.
|
|
914
|
+
this.isRealNode(node) && ans.push(callback(node));
|
|
838
915
|
}
|
|
839
916
|
break;
|
|
840
917
|
}
|
|
@@ -892,7 +969,7 @@ class BinaryTree {
|
|
|
892
969
|
* function on each node.
|
|
893
970
|
* @param callback - The `callback` parameter is a function that will be called for each node in the
|
|
894
971
|
* breadth-first search. It takes a node of type `N` as its argument and returns a value of type
|
|
895
|
-
* `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this.
|
|
972
|
+
* `ReturnType<BTNCallback<N>>`. The default value for this parameter is `this._defaultOneParamCallback
|
|
896
973
|
* @param {N | null | undefined} beginRoot - The `beginRoot` parameter is the starting node for the breadth-first
|
|
897
974
|
* search. It determines from which node the search will begin. If `beginRoot` is `null`, the search
|
|
898
975
|
* will not be performed and an empty array will be returned.
|
|
@@ -901,7 +978,8 @@ class BinaryTree {
|
|
|
901
978
|
* @param includeNull - The choice to output null values during binary tree traversal should be provided.
|
|
902
979
|
* @returns The function `bfs` returns an array of `ReturnType<BTNCallback<N>>[]`.
|
|
903
980
|
*/
|
|
904
|
-
bfs(callback = this.
|
|
981
|
+
bfs(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
982
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
905
983
|
if (!beginRoot)
|
|
906
984
|
return [];
|
|
907
985
|
const ans = [];
|
|
@@ -968,10 +1046,11 @@ class BinaryTree {
|
|
|
968
1046
|
* level in a binary tree. Each inner array contains the return type of the provided callback
|
|
969
1047
|
* function `C` applied to the nodes at that level.
|
|
970
1048
|
*/
|
|
971
|
-
listLevels(callback = this.
|
|
972
|
-
|
|
973
|
-
return [];
|
|
1049
|
+
listLevels(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
1050
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
974
1051
|
const levelsNodes = [];
|
|
1052
|
+
if (!beginRoot)
|
|
1053
|
+
return levelsNodes;
|
|
975
1054
|
if (iterationType === types_1.IterationType.RECURSIVE) {
|
|
976
1055
|
const _recursive = (node, level) => {
|
|
977
1056
|
if (!levelsNodes[level])
|
|
@@ -1022,9 +1101,12 @@ class BinaryTree {
|
|
|
1022
1101
|
* @returns The function `getPredecessor` returns the predecessor node of the given node `node`.
|
|
1023
1102
|
*/
|
|
1024
1103
|
getPredecessor(node) {
|
|
1104
|
+
node = this.ensureNotKey(node);
|
|
1105
|
+
if (!this.isRealNode(node))
|
|
1106
|
+
return undefined;
|
|
1025
1107
|
if (node.left) {
|
|
1026
1108
|
let predecessor = node.left;
|
|
1027
|
-
while (!predecessor || (predecessor.right && predecessor.right !== node)) {
|
|
1109
|
+
while (!this.isRealNode(predecessor) || (this.isRealNode(predecessor.right) && predecessor.right !== node)) {
|
|
1028
1110
|
if (predecessor) {
|
|
1029
1111
|
predecessor = predecessor.right;
|
|
1030
1112
|
}
|
|
@@ -1043,6 +1125,9 @@ class BinaryTree {
|
|
|
1043
1125
|
* if there is no successor, or `undefined` if the input `x` is `undefined`.
|
|
1044
1126
|
*/
|
|
1045
1127
|
getSuccessor(x) {
|
|
1128
|
+
x = this.ensureNotKey(x);
|
|
1129
|
+
if (!x)
|
|
1130
|
+
return undefined;
|
|
1046
1131
|
if (x.right) {
|
|
1047
1132
|
return this.getLeftMost(x.right);
|
|
1048
1133
|
}
|
|
@@ -1058,7 +1143,7 @@ class BinaryTree {
|
|
|
1058
1143
|
* algorithm and returns an array of values obtained by applying a callback function to each node.
|
|
1059
1144
|
* @param callback - The `callback` parameter is a function that will be called on each node in the
|
|
1060
1145
|
* tree. It takes a node of type `N` as input and returns a value of type `ReturnType<BTNCallback<N>>`. The
|
|
1061
|
-
* default value for this parameter is `this.
|
|
1146
|
+
* default value for this parameter is `this._defaultOneParamCallback`.
|
|
1062
1147
|
* @param {DFSOrderPattern} [pattern=in] - The `pattern` parameter in the `morris` function
|
|
1063
1148
|
* determines the order in which the nodes of a binary tree are traversed. It can have one of the
|
|
1064
1149
|
* following values:
|
|
@@ -1067,7 +1152,8 @@ class BinaryTree {
|
|
|
1067
1152
|
* `beginRoot` is `null`, an empty array will be returned.
|
|
1068
1153
|
* @returns The `morris` function returns an array of `ReturnType<BTNCallback<N>>` values.
|
|
1069
1154
|
*/
|
|
1070
|
-
morris(callback = this.
|
|
1155
|
+
morris(callback = this._defaultOneParamCallback, pattern = 'in', beginRoot = this.root) {
|
|
1156
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
1071
1157
|
if (beginRoot === null)
|
|
1072
1158
|
return [];
|
|
1073
1159
|
const ans = [];
|
|
@@ -1192,7 +1278,7 @@ class BinaryTree {
|
|
|
1192
1278
|
}
|
|
1193
1279
|
}
|
|
1194
1280
|
}
|
|
1195
|
-
|
|
1281
|
+
_defaultOneParamCallback = (node) => node.key;
|
|
1196
1282
|
/**
|
|
1197
1283
|
* Swap the data of two nodes in the binary tree.
|
|
1198
1284
|
* @param {N} srcNode - The source node to swap.
|
|
@@ -1200,15 +1286,20 @@ class BinaryTree {
|
|
|
1200
1286
|
* @returns {N} - The destination node after the swap.
|
|
1201
1287
|
*/
|
|
1202
1288
|
_swap(srcNode, destNode) {
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
if (
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1289
|
+
srcNode = this.ensureNotKey(srcNode);
|
|
1290
|
+
destNode = this.ensureNotKey(destNode);
|
|
1291
|
+
if (srcNode && destNode) {
|
|
1292
|
+
const { key, value } = destNode;
|
|
1293
|
+
const tempNode = this.createNode(key, value);
|
|
1294
|
+
if (tempNode) {
|
|
1295
|
+
destNode.key = srcNode.key;
|
|
1296
|
+
destNode.value = srcNode.value;
|
|
1297
|
+
srcNode.key = tempNode.key;
|
|
1298
|
+
srcNode.value = tempNode.value;
|
|
1299
|
+
}
|
|
1300
|
+
return destNode;
|
|
1210
1301
|
}
|
|
1211
|
-
return
|
|
1302
|
+
return undefined;
|
|
1212
1303
|
}
|
|
1213
1304
|
/**
|
|
1214
1305
|
* The function `_addTo` adds a new node to a binary tree if there is an available position.
|
|
@@ -1222,6 +1313,8 @@ class BinaryTree {
|
|
|
1222
1313
|
* If the parent node is null, the function also returns undefined.
|
|
1223
1314
|
*/
|
|
1224
1315
|
_addTo(newNode, parent) {
|
|
1316
|
+
if (this.isNodeKey(parent))
|
|
1317
|
+
parent = this.getNode(parent);
|
|
1225
1318
|
if (parent) {
|
|
1226
1319
|
// When all leaf nodes are null, it will no longer be possible to add new entity nodes to this binary tree.
|
|
1227
1320
|
// In this scenario, null nodes serve as "sentinel nodes," "virtual nodes," or "placeholder nodes."
|
|
@@ -1259,7 +1352,16 @@ class BinaryTree {
|
|
|
1259
1352
|
}
|
|
1260
1353
|
this._root = v;
|
|
1261
1354
|
}
|
|
1355
|
+
/**
|
|
1356
|
+
* The `print` function is used to display a binary tree structure in a visually appealing way.
|
|
1357
|
+
* @param {N | null | undefined} root - The `root` parameter in the `print` function represents the
|
|
1358
|
+
* root node of a binary tree. It can have one of the following types: `BTNKey`, `N`, `null`, or
|
|
1359
|
+
* `undefined`. The default value is `this.root`, which suggests that `this.root` is the
|
|
1360
|
+
*/
|
|
1262
1361
|
print(beginRoot = this.root) {
|
|
1362
|
+
beginRoot = this.ensureNotKey(beginRoot);
|
|
1363
|
+
if (!beginRoot)
|
|
1364
|
+
return;
|
|
1263
1365
|
const display = (root) => {
|
|
1264
1366
|
const [lines, , ,] = _displayAux(root);
|
|
1265
1367
|
for (const line of lines) {
|