data-structure-typed 1.46.8 → 1.47.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.
- package/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/benchmark/report.html +1 -46
- package/benchmark/report.json +11 -422
- package/dist/cjs/data-structures/binary-tree/avl-tree.d.ts +4 -2
- package/dist/cjs/data-structures/binary-tree/avl-tree.js +10 -0
- package/dist/cjs/data-structures/binary-tree/avl-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/binary-tree.d.ts +51 -13
- package/dist/cjs/data-structures/binary-tree/binary-tree.js +153 -55
- package/dist/cjs/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/bst.d.ts +10 -9
- package/dist/cjs/data-structures/binary-tree/bst.js +16 -14
- package/dist/cjs/data-structures/binary-tree/bst.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/rb-tree.d.ts +7 -5
- package/dist/cjs/data-structures/binary-tree/rb-tree.js +32 -23
- package/dist/cjs/data-structures/binary-tree/rb-tree.js.map +1 -1
- package/dist/cjs/data-structures/binary-tree/tree-multimap.d.ts +5 -3
- package/dist/cjs/data-structures/binary-tree/tree-multimap.js +11 -2
- package/dist/cjs/data-structures/binary-tree/tree-multimap.js.map +1 -1
- package/dist/cjs/interfaces/binary-tree.d.ts +3 -3
- package/dist/cjs/types/common.d.ts +5 -4
- package/dist/cjs/types/data-structures/binary-tree/avl-tree.d.ts +2 -1
- package/dist/cjs/types/data-structures/binary-tree/binary-tree.d.ts +3 -1
- package/dist/cjs/types/data-structures/binary-tree/binary-tree.js +0 -6
- package/dist/cjs/types/data-structures/binary-tree/binary-tree.js.map +1 -1
- package/dist/cjs/types/data-structures/binary-tree/bst.d.ts +2 -1
- package/dist/cjs/types/data-structures/binary-tree/rb-tree.d.ts +2 -1
- package/dist/cjs/types/data-structures/binary-tree/tree-multimap.d.ts +2 -1
- package/dist/mjs/data-structures/binary-tree/avl-tree.d.ts +4 -2
- package/dist/mjs/data-structures/binary-tree/avl-tree.js +11 -0
- package/dist/mjs/data-structures/binary-tree/binary-tree.d.ts +51 -13
- package/dist/mjs/data-structures/binary-tree/binary-tree.js +154 -55
- package/dist/mjs/data-structures/binary-tree/bst.d.ts +10 -9
- package/dist/mjs/data-structures/binary-tree/bst.js +17 -14
- package/dist/mjs/data-structures/binary-tree/rb-tree.d.ts +7 -5
- package/dist/mjs/data-structures/binary-tree/rb-tree.js +34 -24
- package/dist/mjs/data-structures/binary-tree/tree-multimap.d.ts +5 -3
- package/dist/mjs/data-structures/binary-tree/tree-multimap.js +12 -2
- package/dist/mjs/interfaces/binary-tree.d.ts +3 -3
- package/dist/mjs/types/common.d.ts +5 -4
- package/dist/mjs/types/data-structures/binary-tree/avl-tree.d.ts +2 -1
- package/dist/mjs/types/data-structures/binary-tree/binary-tree.d.ts +3 -1
- package/dist/mjs/types/data-structures/binary-tree/binary-tree.js +0 -6
- package/dist/mjs/types/data-structures/binary-tree/bst.d.ts +2 -1
- package/dist/mjs/types/data-structures/binary-tree/rb-tree.d.ts +2 -1
- package/dist/mjs/types/data-structures/binary-tree/tree-multimap.d.ts +2 -1
- package/dist/umd/data-structure-typed.js +230 -103
- package/dist/umd/data-structure-typed.min.js +4 -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 +17 -5
- package/src/data-structures/binary-tree/binary-tree.ts +175 -62
- package/src/data-structures/binary-tree/bst.ts +23 -19
- package/src/data-structures/binary-tree/rb-tree.ts +38 -27
- package/src/data-structures/binary-tree/tree-multimap.ts +19 -6
- package/src/interfaces/binary-tree.ts +3 -3
- package/src/types/common.ts +2 -5
- package/src/types/data-structures/binary-tree/avl-tree.ts +5 -1
- package/src/types/data-structures/binary-tree/binary-tree.ts +5 -7
- package/src/types/data-structures/binary-tree/bst.ts +3 -1
- package/src/types/data-structures/binary-tree/rb-tree.ts +3 -1
- package/src/types/data-structures/binary-tree/tree-multimap.ts +3 -1
- package/test/integration/index.html +30 -28
- package/test/performance/data-structures/binary-tree/rb-tree.test.ts +7 -0
- package/test/unit/data-structures/binary-tree/avl-tree.test.ts +57 -1
- package/test/unit/data-structures/binary-tree/binary-tree.test.ts +62 -7
- package/test/unit/data-structures/binary-tree/bst.test.ts +56 -1
- package/test/unit/data-structures/binary-tree/rb-tree.test.ts +98 -42
|
@@ -92,15 +92,17 @@ export class BinaryTreeNode {
|
|
|
92
92
|
* @template N - The type of the binary tree's nodes.
|
|
93
93
|
*/
|
|
94
94
|
export class BinaryTree {
|
|
95
|
-
|
|
95
|
+
options;
|
|
96
96
|
/**
|
|
97
97
|
* Creates a new instance of BinaryTree.
|
|
98
98
|
* @param {BinaryTreeOptions} [options] - The options for the binary tree.
|
|
99
99
|
*/
|
|
100
100
|
constructor(options) {
|
|
101
101
|
if (options) {
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
this.options = { iterationType: IterationType.ITERATIVE, ...options };
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
this.options = { iterationType: IterationType.ITERATIVE };
|
|
104
106
|
}
|
|
105
107
|
this._size = 0;
|
|
106
108
|
}
|
|
@@ -127,6 +129,9 @@ export class BinaryTree {
|
|
|
127
129
|
createNode(key, value) {
|
|
128
130
|
return new BinaryTreeNode(key, value);
|
|
129
131
|
}
|
|
132
|
+
createTree(options) {
|
|
133
|
+
return new BinaryTree({ ...this.options, ...options });
|
|
134
|
+
}
|
|
130
135
|
/**
|
|
131
136
|
* Time Complexity: O(n)
|
|
132
137
|
* Space Complexity: O(1)
|
|
@@ -358,7 +363,7 @@ export class BinaryTree {
|
|
|
358
363
|
* values:
|
|
359
364
|
* @returns the height of the binary tree.
|
|
360
365
|
*/
|
|
361
|
-
getHeight(beginRoot = this.root, iterationType = this.iterationType) {
|
|
366
|
+
getHeight(beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
362
367
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
363
368
|
if (!beginRoot)
|
|
364
369
|
return -1;
|
|
@@ -404,7 +409,7 @@ export class BinaryTree {
|
|
|
404
409
|
* to calculate the minimum height of a binary tree. It can have two possible values:
|
|
405
410
|
* @returns The function `getMinHeight` returns the minimum height of a binary tree.
|
|
406
411
|
*/
|
|
407
|
-
getMinHeight(beginRoot = this.root, iterationType = this.iterationType) {
|
|
412
|
+
getMinHeight(beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
408
413
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
409
414
|
if (!beginRoot)
|
|
410
415
|
return -1;
|
|
@@ -495,7 +500,7 @@ export class BinaryTree {
|
|
|
495
500
|
* traverse the binary tree. It can have two possible values:
|
|
496
501
|
* @returns an array of nodes of type `N`.
|
|
497
502
|
*/
|
|
498
|
-
getNodes(identifier, callback = this._defaultOneParamCallback, onlyOne = false, beginRoot = this.root, iterationType = this.iterationType) {
|
|
503
|
+
getNodes(identifier, callback = this._defaultOneParamCallback, onlyOne = false, beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
499
504
|
if ((!callback || callback === this._defaultOneParamCallback) && identifier instanceof BinaryTreeNode)
|
|
500
505
|
callback = (node => node);
|
|
501
506
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
@@ -557,7 +562,7 @@ export class BinaryTree {
|
|
|
557
562
|
* be performed in a pre-order, in-order, or post-order manner.
|
|
558
563
|
* @returns a boolean value.
|
|
559
564
|
*/
|
|
560
|
-
has(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
565
|
+
has(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
561
566
|
if ((!callback || callback === this._defaultOneParamCallback) && identifier instanceof BinaryTreeNode)
|
|
562
567
|
callback = (node => node);
|
|
563
568
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType).length > 0;
|
|
@@ -587,7 +592,7 @@ export class BinaryTree {
|
|
|
587
592
|
* nodes are visited during the search.
|
|
588
593
|
* @returns a value of type `N | null | undefined`.
|
|
589
594
|
*/
|
|
590
|
-
getNode(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
595
|
+
getNode(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
591
596
|
if ((!callback || callback === this._defaultOneParamCallback) && identifier instanceof BinaryTreeNode)
|
|
592
597
|
callback = (node => node);
|
|
593
598
|
return this.getNodes(identifier, callback, true, beginRoot, iterationType)[0] ?? null;
|
|
@@ -679,7 +684,7 @@ export class BinaryTree {
|
|
|
679
684
|
* @returns The value of the node with the given identifier is being returned. If the node is not
|
|
680
685
|
* found, `undefined` is returned.
|
|
681
686
|
*/
|
|
682
|
-
get(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType) {
|
|
687
|
+
get(identifier, callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
683
688
|
if ((!callback || callback === this._defaultOneParamCallback) && identifier instanceof BinaryTreeNode)
|
|
684
689
|
callback = (node => node);
|
|
685
690
|
return this.getNode(identifier, callback, beginRoot, iterationType)?.value ?? undefined;
|
|
@@ -749,7 +754,7 @@ export class BinaryTree {
|
|
|
749
754
|
* @returns The function `getLeftMost` returns the leftmost node (`N`) in the binary tree. If there
|
|
750
755
|
* is no leftmost node, it returns `null` or `undefined` depending on the input.
|
|
751
756
|
*/
|
|
752
|
-
getLeftMost(beginRoot = this.root, iterationType = this.iterationType) {
|
|
757
|
+
getLeftMost(beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
753
758
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
754
759
|
if (!beginRoot)
|
|
755
760
|
return beginRoot;
|
|
@@ -790,7 +795,7 @@ export class BinaryTree {
|
|
|
790
795
|
* @returns The function `getRightMost` returns the rightmost node (`N`) in a binary tree. If there
|
|
791
796
|
* is no rightmost node, it returns `null` or `undefined`, depending on the input.
|
|
792
797
|
*/
|
|
793
|
-
getRightMost(beginRoot = this.root, iterationType = this.iterationType) {
|
|
798
|
+
getRightMost(beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
794
799
|
// TODO support get right most by passing key in
|
|
795
800
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
796
801
|
if (!beginRoot)
|
|
@@ -829,7 +834,7 @@ export class BinaryTree {
|
|
|
829
834
|
* possible values:
|
|
830
835
|
* @returns a boolean value.
|
|
831
836
|
*/
|
|
832
|
-
isSubtreeBST(beginRoot, iterationType = this.iterationType) {
|
|
837
|
+
isSubtreeBST(beginRoot, iterationType = this.options.iterationType) {
|
|
833
838
|
// TODO there is a bug
|
|
834
839
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
835
840
|
if (!beginRoot)
|
|
@@ -876,7 +881,7 @@ export class BinaryTree {
|
|
|
876
881
|
* expected to be
|
|
877
882
|
* @returns a boolean value.
|
|
878
883
|
*/
|
|
879
|
-
isBST(iterationType = this.iterationType) {
|
|
884
|
+
isBST(iterationType = this.options.iterationType) {
|
|
880
885
|
if (this.root === null)
|
|
881
886
|
return true;
|
|
882
887
|
return this.isSubtreeBST(this.root, iterationType);
|
|
@@ -901,13 +906,13 @@ export class BinaryTree {
|
|
|
901
906
|
* @param iterationType - The `iterationType` parameter determines the type of traversal to be
|
|
902
907
|
* performed on the subtree. It can have two possible values:
|
|
903
908
|
* @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
|
|
904
|
-
* whether
|
|
909
|
+
* whether to include null values in the traversal. If `includeNull` is set to `true`, the
|
|
905
910
|
* traversal will include null values, otherwise it will skip them.
|
|
906
911
|
* @returns The function `subTreeTraverse` returns an array of values that are the result of invoking
|
|
907
912
|
* the `callback` function on each node in the subtree. The type of the array elements is determined
|
|
908
913
|
* by the return type of the `callback` function.
|
|
909
914
|
*/
|
|
910
|
-
subTreeTraverse(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
915
|
+
subTreeTraverse(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType, includeNull = false) {
|
|
911
916
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
912
917
|
const ans = [];
|
|
913
918
|
if (!beginRoot)
|
|
@@ -1134,12 +1139,12 @@ export class BinaryTree {
|
|
|
1134
1139
|
* @param iterationType - The `iterationType` parameter determines the type of iteration to be
|
|
1135
1140
|
* performed during the breadth-first search (BFS). It can have two possible values:
|
|
1136
1141
|
* @param [includeNull=false] - The `includeNull` parameter is a boolean flag that determines whether
|
|
1137
|
-
*
|
|
1142
|
+
* to include null values in the breadth-first search traversal. If `includeNull` is set to
|
|
1138
1143
|
* `true`, null values will be included in the traversal, otherwise they will be skipped.
|
|
1139
1144
|
* @returns an array of values that are the result of invoking the callback function on each node in
|
|
1140
1145
|
* the breadth-first traversal of a binary tree.
|
|
1141
1146
|
*/
|
|
1142
|
-
bfs(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
1147
|
+
bfs(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType, includeNull = false) {
|
|
1143
1148
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
1144
1149
|
if (!beginRoot)
|
|
1145
1150
|
return [];
|
|
@@ -1211,12 +1216,12 @@ export class BinaryTree {
|
|
|
1211
1216
|
* @param iterationType - The `iterationType` parameter determines the type of iteration to be
|
|
1212
1217
|
* performed on the tree. It can have two possible values:
|
|
1213
1218
|
* @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
|
|
1214
|
-
* whether
|
|
1219
|
+
* whether to include null values in the resulting levels. If `includeNull` is set to `true`,
|
|
1215
1220
|
* null values will be included in the levels. If `includeNull` is set to `false`, null values will
|
|
1216
1221
|
* be excluded
|
|
1217
1222
|
* @returns The function `listLevels` returns a two-dimensional array of type `ReturnType<C>[][]`.
|
|
1218
1223
|
*/
|
|
1219
|
-
listLevels(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.iterationType, includeNull = false) {
|
|
1224
|
+
listLevels(callback = this._defaultOneParamCallback, beginRoot = this.root, iterationType = this.options.iterationType, includeNull = false) {
|
|
1220
1225
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
1221
1226
|
const levelsNodes = [];
|
|
1222
1227
|
if (!beginRoot)
|
|
@@ -1415,6 +1420,74 @@ export class BinaryTree {
|
|
|
1415
1420
|
}
|
|
1416
1421
|
return ans;
|
|
1417
1422
|
}
|
|
1423
|
+
/**
|
|
1424
|
+
* The `forEach` function iterates over each entry in a tree and calls a callback function with the
|
|
1425
|
+
* entry and the tree as arguments.
|
|
1426
|
+
* @param callback - The callback parameter is a function that will be called for each entry in the
|
|
1427
|
+
* tree. It takes two parameters: entry and tree.
|
|
1428
|
+
*/
|
|
1429
|
+
forEach(callback) {
|
|
1430
|
+
for (const entry of this) {
|
|
1431
|
+
callback(entry, this);
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
/**
|
|
1435
|
+
* The `filter` function creates a new tree by iterating over the entries of the current tree and
|
|
1436
|
+
* adding the entries that satisfy the given predicate.
|
|
1437
|
+
* @param predicate - The `predicate` parameter is a function that takes two arguments: `entry` and
|
|
1438
|
+
* `tree`.
|
|
1439
|
+
* @returns The `filter` method is returning a new tree object that contains only the entries that
|
|
1440
|
+
* satisfy the given predicate function.
|
|
1441
|
+
*/
|
|
1442
|
+
filter(predicate) {
|
|
1443
|
+
const newTree = this.createTree();
|
|
1444
|
+
for (const [key, value] of this) {
|
|
1445
|
+
if (predicate([key, value], this)) {
|
|
1446
|
+
newTree.add(key, value);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
return newTree;
|
|
1450
|
+
}
|
|
1451
|
+
// TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
|
|
1452
|
+
// map<NV>(callback: (entry: [BTNKey, V | undefined], tree: this) => NV) {
|
|
1453
|
+
// const newTree = this.createTree();
|
|
1454
|
+
// for (const [key, value] of this) {
|
|
1455
|
+
// newTree.add(key, callback([key, value], this));
|
|
1456
|
+
// }
|
|
1457
|
+
// return newTree;
|
|
1458
|
+
// }
|
|
1459
|
+
/**
|
|
1460
|
+
* The `map` function creates a new tree by applying a callback function to each entry in the current
|
|
1461
|
+
* tree.
|
|
1462
|
+
* @param callback - The callback parameter is a function that takes two arguments: entry and tree.
|
|
1463
|
+
* @returns The `map` method is returning a new tree object.
|
|
1464
|
+
*/
|
|
1465
|
+
map(callback) {
|
|
1466
|
+
const newTree = this.createTree();
|
|
1467
|
+
for (const [key, value] of this) {
|
|
1468
|
+
newTree.add(key, callback([key, value], this));
|
|
1469
|
+
}
|
|
1470
|
+
return newTree;
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* The `reduce` function iterates over the entries of a tree and applies a callback function to each
|
|
1474
|
+
* entry, accumulating a single value.
|
|
1475
|
+
* @param callback - The callback parameter is a function that takes three arguments: accumulator,
|
|
1476
|
+
* entry, and tree. It is called for each entry in the tree and is used to accumulate a single value
|
|
1477
|
+
* based on the logic defined in the callback function.
|
|
1478
|
+
* @param {T} initialValue - The initialValue parameter is the initial value of the accumulator. It
|
|
1479
|
+
* is the value that will be passed as the first argument to the callback function when reducing the
|
|
1480
|
+
* elements of the tree.
|
|
1481
|
+
* @returns The `reduce` method is returning the final value of the accumulator after iterating over
|
|
1482
|
+
* all the entries in the tree and applying the callback function to each entry.
|
|
1483
|
+
*/
|
|
1484
|
+
reduce(callback, initialValue) {
|
|
1485
|
+
let accumulator = initialValue;
|
|
1486
|
+
for (const [key, value] of this) {
|
|
1487
|
+
accumulator = callback(accumulator, [key, value], this);
|
|
1488
|
+
}
|
|
1489
|
+
return accumulator;
|
|
1490
|
+
}
|
|
1418
1491
|
/**
|
|
1419
1492
|
* The above function is an iterator for a binary tree that can be used to traverse the tree in
|
|
1420
1493
|
* either an iterative or recursive manner.
|
|
@@ -1425,78 +1498,104 @@ export class BinaryTree {
|
|
|
1425
1498
|
* binary tree nodes in a specific order.
|
|
1426
1499
|
*/
|
|
1427
1500
|
*[Symbol.iterator](node = this.root) {
|
|
1428
|
-
if (!node)
|
|
1501
|
+
if (!node)
|
|
1429
1502
|
return;
|
|
1430
|
-
|
|
1431
|
-
if (this.iterationType === IterationType.ITERATIVE) {
|
|
1503
|
+
if (this.options.iterationType === IterationType.ITERATIVE) {
|
|
1432
1504
|
const stack = [];
|
|
1433
1505
|
let current = node;
|
|
1434
1506
|
while (current || stack.length > 0) {
|
|
1435
|
-
while (current) {
|
|
1507
|
+
while (current && !isNaN(current.key)) {
|
|
1436
1508
|
stack.push(current);
|
|
1437
1509
|
current = current.left;
|
|
1438
1510
|
}
|
|
1439
1511
|
current = stack.pop();
|
|
1440
|
-
if (current)
|
|
1441
|
-
yield current.key;
|
|
1442
|
-
if (current)
|
|
1512
|
+
if (current && !isNaN(current.key)) {
|
|
1513
|
+
yield [current.key, current.value];
|
|
1443
1514
|
current = current.right;
|
|
1515
|
+
}
|
|
1444
1516
|
}
|
|
1445
1517
|
}
|
|
1446
1518
|
else {
|
|
1447
|
-
if (node.left) {
|
|
1519
|
+
if (node.left && !isNaN(node.key)) {
|
|
1448
1520
|
yield* this[Symbol.iterator](node.left);
|
|
1449
1521
|
}
|
|
1450
|
-
yield node.key;
|
|
1451
|
-
if (node.right) {
|
|
1522
|
+
yield [node.key, node.value];
|
|
1523
|
+
if (node.right && !isNaN(node.key)) {
|
|
1452
1524
|
yield* this[Symbol.iterator](node.right);
|
|
1453
1525
|
}
|
|
1454
1526
|
}
|
|
1455
1527
|
}
|
|
1456
1528
|
/**
|
|
1457
1529
|
* The `print` function is used to display a binary tree structure in a visually appealing way.
|
|
1458
|
-
* @param {N | null | undefined} beginRoot - The `root` parameter is of type `BTNKey | N | null |
|
|
1530
|
+
* @param {BTNKey | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `BTNKey | N | null |
|
|
1459
1531
|
* undefined`. It represents the root node of a binary tree. The root node can have one of the
|
|
1460
1532
|
* following types:
|
|
1533
|
+
* @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.
|
|
1461
1534
|
*/
|
|
1462
|
-
print(beginRoot = this.root) {
|
|
1535
|
+
print(beginRoot = this.root, options) {
|
|
1536
|
+
const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
|
|
1463
1537
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
1464
1538
|
if (!beginRoot)
|
|
1465
1539
|
return;
|
|
1540
|
+
if (opts.isShowUndefined)
|
|
1541
|
+
console.log(`U for undefined
|
|
1542
|
+
`);
|
|
1543
|
+
if (opts.isShowNull)
|
|
1544
|
+
console.log(`N for null
|
|
1545
|
+
`);
|
|
1546
|
+
if (opts.isShowRedBlackNIL)
|
|
1547
|
+
console.log(`S for Sentinel Node
|
|
1548
|
+
`);
|
|
1466
1549
|
const display = (root) => {
|
|
1467
|
-
const [lines, , ,] = this._displayAux(root);
|
|
1550
|
+
const [lines, , ,] = this._displayAux(root, opts);
|
|
1468
1551
|
for (const line of lines) {
|
|
1469
1552
|
console.log(line);
|
|
1470
1553
|
}
|
|
1471
1554
|
};
|
|
1472
1555
|
display(beginRoot);
|
|
1473
1556
|
}
|
|
1474
|
-
_displayAux(node) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1557
|
+
_displayAux(node, options) {
|
|
1558
|
+
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
1559
|
+
const emptyDisplayLayout = [['─'], 1, 0, 0];
|
|
1560
|
+
// Check if node is null or undefined or key is NaN
|
|
1561
|
+
if (node === null && !isShowNull) {
|
|
1562
|
+
return emptyDisplayLayout;
|
|
1563
|
+
}
|
|
1564
|
+
else if (node === undefined && !isShowUndefined) {
|
|
1565
|
+
return emptyDisplayLayout;
|
|
1566
|
+
}
|
|
1567
|
+
else if (node !== null && node !== undefined && isNaN(node.key) && !isShowRedBlackNIL) {
|
|
1568
|
+
return emptyDisplayLayout;
|
|
1477
1569
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
return
|
|
1570
|
+
else if (node !== null && node !== undefined) {
|
|
1571
|
+
// Display logic of normal nodes
|
|
1572
|
+
const key = node.key, line = isNaN(key) ? 'S' : key.toString(), width = line.length;
|
|
1573
|
+
return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options));
|
|
1482
1574
|
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
const
|
|
1497
|
-
|
|
1575
|
+
else {
|
|
1576
|
+
// For cases where none of the conditions are met, null, undefined, and NaN nodes are not displayed
|
|
1577
|
+
const line = node === undefined ? 'U' : 'N', width = line.length;
|
|
1578
|
+
return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0]);
|
|
1579
|
+
}
|
|
1580
|
+
function _buildNodeDisplay(line, width, left, right) {
|
|
1581
|
+
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
|
|
1582
|
+
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
|
|
1583
|
+
const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
|
|
1584
|
+
+ '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
|
|
1585
|
+
+ line
|
|
1586
|
+
+ '_'.repeat(Math.max(0, rightMiddle))
|
|
1587
|
+
+ ' '.repeat(Math.max(0, rightWidth - rightMiddle));
|
|
1588
|
+
const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
|
|
1589
|
+
+ ' '.repeat(width)
|
|
1590
|
+
+ (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
|
|
1591
|
+
const mergedLines = [firstLine, secondLine];
|
|
1592
|
+
for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
|
|
1593
|
+
const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
|
|
1594
|
+
const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
|
|
1595
|
+
mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
|
|
1596
|
+
}
|
|
1597
|
+
return [mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
|
|
1498
1598
|
}
|
|
1499
|
-
return [mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
|
|
1500
1599
|
}
|
|
1501
1600
|
_defaultOneParamCallback = (node) => node.key;
|
|
1502
1601
|
/**
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
8
|
+
import type { BSTNested, BSTNodeNested, BSTOptions, BTNCallback, BTNKey } from '../../types';
|
|
9
9
|
import { CP, IterationType } from '../../types';
|
|
10
10
|
import { BinaryTree, BinaryTreeNode } from './binary-tree';
|
|
11
11
|
import { IBinaryTree } from '../../interfaces';
|
|
@@ -33,7 +33,8 @@ export declare class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>
|
|
|
33
33
|
*/
|
|
34
34
|
set right(v: N | undefined);
|
|
35
35
|
}
|
|
36
|
-
export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>> extends BinaryTree<V, N> implements IBinaryTree<V, N> {
|
|
36
|
+
export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>, TREE extends BST<V, N, TREE> = BST<V, N, BSTNested<V, N>>> extends BinaryTree<V, N, TREE> implements IBinaryTree<V, N, TREE> {
|
|
37
|
+
options: BSTOptions;
|
|
37
38
|
/**
|
|
38
39
|
* The constructor function initializes a binary search tree with an optional comparator function.
|
|
39
40
|
* @param {BSTOptions} [options] - An optional object that contains additional configuration options
|
|
@@ -54,6 +55,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
54
55
|
* @returns a new instance of the BSTNode class with the specified key and value.
|
|
55
56
|
*/
|
|
56
57
|
createNode(key: BTNKey, value?: V): N;
|
|
58
|
+
createTree(options?: BSTOptions): TREE;
|
|
57
59
|
/**
|
|
58
60
|
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
|
|
59
61
|
* Space Complexity: O(1) - Constant space is used.
|
|
@@ -95,7 +97,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
95
97
|
* current instance of the binary search tree
|
|
96
98
|
* @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values.
|
|
97
99
|
*/
|
|
98
|
-
addMany(keysOrNodes: (BTNKey | N | undefined)[], data?: (V | undefined)[], isBalanceAdd?: boolean, iterationType?: IterationType): (N | undefined)[];
|
|
100
|
+
addMany(keysOrNodes: (BTNKey | N | undefined)[], data?: (V | undefined)[], isBalanceAdd?: boolean, iterationType?: IterationType | undefined): (N | undefined)[];
|
|
99
101
|
/**
|
|
100
102
|
* Time Complexity: O(log n) - Average case for a balanced tree.
|
|
101
103
|
* Space Complexity: O(1) - Constant space is used.
|
|
@@ -115,7 +117,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
115
117
|
* the key of the leftmost node if the comparison result is greater than, and the key of the
|
|
116
118
|
* rightmost node otherwise. If no node is found, it returns 0.
|
|
117
119
|
*/
|
|
118
|
-
lastKey(beginRoot?: BTNKey | N | undefined, iterationType?: IterationType): BTNKey;
|
|
120
|
+
lastKey(beginRoot?: BTNKey | N | undefined, iterationType?: IterationType | undefined): BTNKey;
|
|
119
121
|
/**
|
|
120
122
|
* Time Complexity: O(log n) - Average case for a balanced tree.
|
|
121
123
|
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
|
|
@@ -172,7 +174,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
172
174
|
* performed on the binary tree. It can have two possible values:
|
|
173
175
|
* @returns The method returns an array of nodes (`N[]`).
|
|
174
176
|
*/
|
|
175
|
-
getNodes<C extends BTNCallback<N>>(identifier: ReturnType<C> | undefined, callback?: C, onlyOne?: boolean, beginRoot?: BTNKey | N | undefined, iterationType?: IterationType): N[];
|
|
177
|
+
getNodes<C extends BTNCallback<N>>(identifier: ReturnType<C> | undefined, callback?: C, onlyOne?: boolean, beginRoot?: BTNKey | N | undefined, iterationType?: IterationType | undefined): N[];
|
|
176
178
|
/**
|
|
177
179
|
* Time Complexity: O(log n) - Average case for a balanced tree. O(n) - Visiting each node once when identifier is not node's key.
|
|
178
180
|
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
|
|
@@ -198,7 +200,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
198
200
|
* @returns The function `lesserOrGreaterTraverse` returns an array of values of type
|
|
199
201
|
* `ReturnType<C>`, which is the return type of the callback function passed as an argument.
|
|
200
202
|
*/
|
|
201
|
-
lesserOrGreaterTraverse<C extends BTNCallback<N>>(callback?: C, lesserOrGreater?: CP, targetNode?: BTNKey | N | undefined, iterationType?: IterationType): ReturnType<C>[];
|
|
203
|
+
lesserOrGreaterTraverse<C extends BTNCallback<N>>(callback?: C, lesserOrGreater?: CP, targetNode?: BTNKey | N | undefined, iterationType?: IterationType | undefined): ReturnType<C>[];
|
|
202
204
|
/**
|
|
203
205
|
* Balancing Adjustment:
|
|
204
206
|
* Perfectly Balanced Binary Tree: Since the balance of a perfectly balanced binary tree is already fixed, no additional balancing adjustment is needed. Any insertion or deletion operation will disrupt the perfect balance, often requiring a complete reconstruction of the tree.
|
|
@@ -223,7 +225,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
223
225
|
* values:
|
|
224
226
|
* @returns The function `perfectlyBalance` returns a boolean value.
|
|
225
227
|
*/
|
|
226
|
-
perfectlyBalance(iterationType?: IterationType): boolean;
|
|
228
|
+
perfectlyBalance(iterationType?: IterationType | undefined): boolean;
|
|
227
229
|
/**
|
|
228
230
|
* Time Complexity: O(n) - Visiting each node once.
|
|
229
231
|
* Space Complexity: O(log n) - Space for the recursive call stack in the worst case.
|
|
@@ -237,8 +239,7 @@ export declare class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNe
|
|
|
237
239
|
* to check if the AVL tree is balanced. It can have two possible values:
|
|
238
240
|
* @returns a boolean value.
|
|
239
241
|
*/
|
|
240
|
-
isAVLBalanced(iterationType?: IterationType): boolean;
|
|
241
|
-
protected _comparator: BSTComparator;
|
|
242
|
+
isAVLBalanced(iterationType?: IterationType | undefined): boolean;
|
|
242
243
|
protected _setRoot(v: N | undefined): void;
|
|
243
244
|
/**
|
|
244
245
|
* The function compares two values using a comparator function and returns whether the first value
|
|
@@ -45,6 +45,7 @@ export class BSTNode extends BinaryTreeNode {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
export class BST extends BinaryTree {
|
|
48
|
+
options;
|
|
48
49
|
/**
|
|
49
50
|
* The constructor function initializes a binary search tree with an optional comparator function.
|
|
50
51
|
* @param {BSTOptions} [options] - An optional object that contains additional configuration options
|
|
@@ -52,13 +53,13 @@ export class BST extends BinaryTree {
|
|
|
52
53
|
*/
|
|
53
54
|
constructor(options) {
|
|
54
55
|
super(options);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
56
|
+
if (options) {
|
|
57
|
+
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options };
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
|
|
61
61
|
}
|
|
62
|
+
this._root = undefined;
|
|
62
63
|
}
|
|
63
64
|
_root;
|
|
64
65
|
/**
|
|
@@ -78,6 +79,9 @@ export class BST extends BinaryTree {
|
|
|
78
79
|
createNode(key, value) {
|
|
79
80
|
return new BSTNode(key, value);
|
|
80
81
|
}
|
|
82
|
+
createTree(options) {
|
|
83
|
+
return new BST({ ...this.options, ...options });
|
|
84
|
+
}
|
|
81
85
|
/**
|
|
82
86
|
* Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
|
|
83
87
|
* Space Complexity: O(1) - Constant space is used.
|
|
@@ -195,7 +199,7 @@ export class BST extends BinaryTree {
|
|
|
195
199
|
* current instance of the binary search tree
|
|
196
200
|
* @returns The function `addMany` returns an array of nodes (`N`) or `undefined` values.
|
|
197
201
|
*/
|
|
198
|
-
addMany(keysOrNodes, data, isBalanceAdd = true, iterationType = this.iterationType) {
|
|
202
|
+
addMany(keysOrNodes, data, isBalanceAdd = true, iterationType = this.options.iterationType) {
|
|
199
203
|
// TODO this addMany function is inefficient, it should be optimized
|
|
200
204
|
function hasNoUndefined(arr) {
|
|
201
205
|
return arr.indexOf(undefined) === -1;
|
|
@@ -283,7 +287,7 @@ export class BST extends BinaryTree {
|
|
|
283
287
|
* the key of the leftmost node if the comparison result is greater than, and the key of the
|
|
284
288
|
* rightmost node otherwise. If no node is found, it returns 0.
|
|
285
289
|
*/
|
|
286
|
-
lastKey(beginRoot = this.root, iterationType = this.iterationType) {
|
|
290
|
+
lastKey(beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
287
291
|
if (this._compare(0, 1) === CP.lt)
|
|
288
292
|
return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
|
|
289
293
|
else if (this._compare(0, 1) === CP.gt)
|
|
@@ -379,7 +383,7 @@ export class BST extends BinaryTree {
|
|
|
379
383
|
* performed on the binary tree. It can have two possible values:
|
|
380
384
|
* @returns The method returns an array of nodes (`N[]`).
|
|
381
385
|
*/
|
|
382
|
-
getNodes(identifier, callback = this._defaultOneParamCallback, onlyOne = false, beginRoot = this.root, iterationType = this.iterationType) {
|
|
386
|
+
getNodes(identifier, callback = this._defaultOneParamCallback, onlyOne = false, beginRoot = this.root, iterationType = this.options.iterationType) {
|
|
383
387
|
beginRoot = this.ensureNotKey(beginRoot);
|
|
384
388
|
if (!beginRoot)
|
|
385
389
|
return [];
|
|
@@ -460,7 +464,7 @@ export class BST extends BinaryTree {
|
|
|
460
464
|
* @returns The function `lesserOrGreaterTraverse` returns an array of values of type
|
|
461
465
|
* `ReturnType<C>`, which is the return type of the callback function passed as an argument.
|
|
462
466
|
*/
|
|
463
|
-
lesserOrGreaterTraverse(callback = this._defaultOneParamCallback, lesserOrGreater = CP.lt, targetNode = this.root, iterationType = this.iterationType) {
|
|
467
|
+
lesserOrGreaterTraverse(callback = this._defaultOneParamCallback, lesserOrGreater = CP.lt, targetNode = this.root, iterationType = this.options.iterationType) {
|
|
464
468
|
targetNode = this.ensureNotKey(targetNode);
|
|
465
469
|
const ans = [];
|
|
466
470
|
if (!targetNode)
|
|
@@ -524,7 +528,7 @@ export class BST extends BinaryTree {
|
|
|
524
528
|
* values:
|
|
525
529
|
* @returns The function `perfectlyBalance` returns a boolean value.
|
|
526
530
|
*/
|
|
527
|
-
perfectlyBalance(iterationType = this.iterationType) {
|
|
531
|
+
perfectlyBalance(iterationType = this.options.iterationType) {
|
|
528
532
|
const sorted = this.dfs(node => node, 'in'), n = sorted.length;
|
|
529
533
|
this.clear();
|
|
530
534
|
if (sorted.length < 1)
|
|
@@ -574,7 +578,7 @@ export class BST extends BinaryTree {
|
|
|
574
578
|
* to check if the AVL tree is balanced. It can have two possible values:
|
|
575
579
|
* @returns a boolean value.
|
|
576
580
|
*/
|
|
577
|
-
isAVLBalanced(iterationType = this.iterationType) {
|
|
581
|
+
isAVLBalanced(iterationType = this.options.iterationType) {
|
|
578
582
|
if (!this.root)
|
|
579
583
|
return true;
|
|
580
584
|
let balanced = true;
|
|
@@ -619,7 +623,6 @@ export class BST extends BinaryTree {
|
|
|
619
623
|
}
|
|
620
624
|
return balanced;
|
|
621
625
|
}
|
|
622
|
-
_comparator = (a, b) => a - b;
|
|
623
626
|
_setRoot(v) {
|
|
624
627
|
if (v) {
|
|
625
628
|
v.parent = undefined;
|
|
@@ -635,7 +638,7 @@ export class BST extends BinaryTree {
|
|
|
635
638
|
* than), CP.lt (less than), or CP.eq (equal).
|
|
636
639
|
*/
|
|
637
640
|
_compare(a, b) {
|
|
638
|
-
const compared = this.
|
|
641
|
+
const compared = this.options.comparator(a, b);
|
|
639
642
|
if (compared > 0)
|
|
640
643
|
return CP.gt;
|
|
641
644
|
else if (compared < 0)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
import { BiTreeDeleteResult, BTNCallback, BTNKey, IterationType, RBTNColor, RBTreeOptions, RedBlackTreeNodeNested } from '../../types';
|
|
8
|
+
import { BiTreeDeleteResult, BTNCallback, BTNKey, IterationType, RBTNColor, RBTreeOptions, RedBlackTreeNested, RedBlackTreeNodeNested } from '../../types';
|
|
9
9
|
import { BST, BSTNode } from './bst';
|
|
10
10
|
import { IBinaryTree } from '../../interfaces';
|
|
11
11
|
export declare class RedBlackTreeNode<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNodeNested<V>> extends BSTNode<V, N> {
|
|
@@ -15,12 +15,13 @@ export declare class RedBlackTreeNode<V = any, N extends RedBlackTreeNode<V, N>
|
|
|
15
15
|
/**
|
|
16
16
|
* 1. Each node is either red or black.
|
|
17
17
|
* 2. The root node is always black.
|
|
18
|
-
* 3. Leaf nodes are typically
|
|
18
|
+
* 3. Leaf nodes are typically Sentinel nodes and are considered black.
|
|
19
19
|
* 4. Red nodes must have black children.
|
|
20
20
|
* 5. Black balance: Every path from any node to each of its leaf nodes contains the same number of black nodes.
|
|
21
21
|
*/
|
|
22
|
-
export declare class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNode<V, RedBlackTreeNodeNested<V>>> extends BST<V, N> implements IBinaryTree<V, N> {
|
|
23
|
-
|
|
22
|
+
export declare class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = RedBlackTreeNode<V, RedBlackTreeNodeNested<V>>, TREE extends RedBlackTree<V, N, TREE> = RedBlackTree<V, N, RedBlackTreeNested<V, N>>> extends BST<V, N, TREE> implements IBinaryTree<V, N, TREE> {
|
|
23
|
+
Sentinel: N;
|
|
24
|
+
options: RBTreeOptions;
|
|
24
25
|
/**
|
|
25
26
|
* The constructor function initializes a Red-Black Tree with an optional set of options.
|
|
26
27
|
* @param {RBTreeOptions} [options] - The `options` parameter is an optional object that can be
|
|
@@ -31,6 +32,8 @@ export declare class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = Re
|
|
|
31
32
|
get root(): N;
|
|
32
33
|
protected _size: number;
|
|
33
34
|
get size(): number;
|
|
35
|
+
createNode(key: BTNKey, value?: V, color?: RBTNColor): N;
|
|
36
|
+
createTree(options?: RBTreeOptions): TREE;
|
|
34
37
|
/**
|
|
35
38
|
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
|
|
36
39
|
* Space Complexity: O(1)
|
|
@@ -47,7 +50,6 @@ export declare class RedBlackTree<V = any, N extends RedBlackTreeNode<V, N> = Re
|
|
|
47
50
|
* @returns The method returns either a node (`N`) or `undefined`.
|
|
48
51
|
*/
|
|
49
52
|
add(keyOrNode: BTNKey | N | null | undefined, value?: V): N | undefined;
|
|
50
|
-
createNode(key: BTNKey, value?: V, color?: RBTNColor): N;
|
|
51
53
|
/**
|
|
52
54
|
* Time Complexity: O(log n) on average (where n is the number of nodes in the tree)
|
|
53
55
|
* Space Complexity: O(1)
|