priority-queue-typed 1.46.8 → 1.46.9

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 (31) hide show
  1. package/dist/data-structures/binary-tree/avl-tree.d.ts +4 -2
  2. package/dist/data-structures/binary-tree/avl-tree.js +10 -0
  3. package/dist/data-structures/binary-tree/binary-tree.d.ts +19 -13
  4. package/dist/data-structures/binary-tree/binary-tree.js +121 -55
  5. package/dist/data-structures/binary-tree/bst.d.ts +10 -9
  6. package/dist/data-structures/binary-tree/bst.js +16 -14
  7. package/dist/data-structures/binary-tree/rb-tree.d.ts +7 -5
  8. package/dist/data-structures/binary-tree/rb-tree.js +32 -23
  9. package/dist/data-structures/binary-tree/tree-multimap.d.ts +5 -3
  10. package/dist/data-structures/binary-tree/tree-multimap.js +11 -2
  11. package/dist/interfaces/binary-tree.d.ts +3 -3
  12. package/dist/types/common.d.ts +5 -4
  13. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +2 -1
  14. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +3 -1
  15. package/dist/types/data-structures/binary-tree/binary-tree.js +0 -6
  16. package/dist/types/data-structures/binary-tree/bst.d.ts +2 -1
  17. package/dist/types/data-structures/binary-tree/rb-tree.d.ts +2 -1
  18. package/dist/types/data-structures/binary-tree/tree-multimap.d.ts +2 -1
  19. package/package.json +2 -2
  20. package/src/data-structures/binary-tree/avl-tree.ts +17 -5
  21. package/src/data-structures/binary-tree/binary-tree.ts +143 -62
  22. package/src/data-structures/binary-tree/bst.ts +23 -19
  23. package/src/data-structures/binary-tree/rb-tree.ts +38 -27
  24. package/src/data-structures/binary-tree/tree-multimap.ts +19 -6
  25. package/src/interfaces/binary-tree.ts +3 -3
  26. package/src/types/common.ts +2 -5
  27. package/src/types/data-structures/binary-tree/avl-tree.ts +5 -1
  28. package/src/types/data-structures/binary-tree/binary-tree.ts +5 -7
  29. package/src/types/data-structures/binary-tree/bst.ts +3 -1
  30. package/src/types/data-structures/binary-tree/rb-tree.ts +3 -1
  31. package/src/types/data-structures/binary-tree/tree-multimap.ts +3 -1
@@ -7,7 +7,15 @@
7
7
  */
8
8
 
9
9
  import type { BinaryTreeNodeNested, BinaryTreeOptions, BTNCallback, BTNKey } from '../../types';
10
- import { BiTreeDeleteResult, DFSOrderPattern, FamilyPosition, IterationType } from '../../types';
10
+ import {
11
+ BinaryTreeNested,
12
+ BinaryTreePrintOptions,
13
+ BiTreeDeleteResult,
14
+ DFSOrderPattern,
15
+ FamilyPosition,
16
+ IterationType,
17
+ NodeDisplayLayout
18
+ } from '../../types';
11
19
  import { IBinaryTree } from '../../interfaces';
12
20
  import { trampoline } from '../../utils';
13
21
  import { Queue } from '../queue';
@@ -107,9 +115,10 @@ export class BinaryTreeNode<V = any, N extends BinaryTreeNode<V, N> = BinaryTree
107
115
  * Represents a binary tree data structure.
108
116
  * @template N - The type of the binary tree's nodes.
109
117
  */
110
- export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode<V, BinaryTreeNodeNested<V>>>
111
- implements IBinaryTree<V, N> {
112
- iterationType: IterationType = IterationType.ITERATIVE;
118
+ 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>>>
119
+ implements IBinaryTree<V, N, TREE> {
120
+
121
+ options: BinaryTreeOptions;
113
122
 
114
123
  /**
115
124
  * Creates a new instance of BinaryTree.
@@ -117,9 +126,11 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
117
126
  */
118
127
  constructor(options?: BinaryTreeOptions) {
119
128
  if (options) {
120
- const { iterationType = IterationType.ITERATIVE } = options;
121
- this.iterationType = iterationType;
129
+ this.options = { iterationType: IterationType.ITERATIVE, ...options }
130
+ } else {
131
+ this.options = { iterationType: IterationType.ITERATIVE };
122
132
  }
133
+
123
134
  this._size = 0;
124
135
  }
125
136
 
@@ -151,6 +162,10 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
151
162
  return new BinaryTreeNode<V, N>(key, value) as N;
152
163
  }
153
164
 
165
+ createTree(options?: BinaryTreeOptions): TREE {
166
+ return new BinaryTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
167
+ }
168
+
154
169
  /**
155
170
  * Time Complexity: O(n)
156
171
  * Space Complexity: O(1)
@@ -397,7 +412,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
397
412
  * values:
398
413
  * @returns the height of the binary tree.
399
414
  */
400
- getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
415
+ getHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.options.iterationType): number {
401
416
  beginRoot = this.ensureNotKey(beginRoot);
402
417
  if (!beginRoot) return -1;
403
418
 
@@ -446,7 +461,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
446
461
  * to calculate the minimum height of a binary tree. It can have two possible values:
447
462
  * @returns The function `getMinHeight` returns the minimum height of a binary tree.
448
463
  */
449
- getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.iterationType): number {
464
+ getMinHeight(beginRoot: BTNKey | N | null | undefined = this.root, iterationType = this.options.iterationType): number {
450
465
  beginRoot = this.ensureNotKey(beginRoot);
451
466
  if (!beginRoot) return -1;
452
467
 
@@ -568,7 +583,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
568
583
  callback: C = this._defaultOneParamCallback as C,
569
584
  onlyOne = false,
570
585
  beginRoot: BTNKey | N | null | undefined = this.root,
571
- iterationType = this.iterationType
586
+ iterationType = this.options.iterationType
572
587
  ): N[] {
573
588
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
574
589
  callback = (node => node) as C;
@@ -657,7 +672,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
657
672
  identifier: ReturnType<C> | null | undefined,
658
673
  callback: C = this._defaultOneParamCallback as C,
659
674
  beginRoot: BTNKey | N | null | undefined = this.root,
660
- iterationType = this.iterationType
675
+ iterationType = this.options.iterationType
661
676
  ): boolean {
662
677
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
663
678
  callback = (node => node) as C;
@@ -716,7 +731,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
716
731
  identifier: ReturnType<C> | null | undefined,
717
732
  callback: C = this._defaultOneParamCallback as C,
718
733
  beginRoot: BTNKey | N | null | undefined = this.root,
719
- iterationType = this.iterationType
734
+ iterationType = this.options.iterationType
720
735
  ): N | null | undefined {
721
736
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
722
737
  callback = (node => node) as C;
@@ -835,7 +850,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
835
850
  identifier: ReturnType<C> | null | undefined,
836
851
  callback: C = this._defaultOneParamCallback as C,
837
852
  beginRoot: BTNKey | N | null | undefined = this.root,
838
- iterationType = this.iterationType
853
+ iterationType = this.options.iterationType
839
854
  ): V | undefined {
840
855
  if ((!callback || callback === this._defaultOneParamCallback) && (identifier as any) instanceof BinaryTreeNode)
841
856
  callback = (node => node) as C;
@@ -916,7 +931,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
916
931
  */
917
932
  getLeftMost(
918
933
  beginRoot: BTNKey | N | null | undefined = this.root,
919
- iterationType = this.iterationType
934
+ iterationType = this.options.iterationType
920
935
  ): N | null | undefined {
921
936
  beginRoot = this.ensureNotKey(beginRoot);
922
937
 
@@ -962,7 +977,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
962
977
  */
963
978
  getRightMost(
964
979
  beginRoot: BTNKey | N | null | undefined = this.root,
965
- iterationType = this.iterationType
980
+ iterationType = this.options.iterationType
966
981
  ): N | null | undefined {
967
982
  // TODO support get right most by passing key in
968
983
  beginRoot = this.ensureNotKey(beginRoot);
@@ -1003,7 +1018,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1003
1018
  * possible values:
1004
1019
  * @returns a boolean value.
1005
1020
  */
1006
- isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.iterationType): boolean {
1021
+ isSubtreeBST(beginRoot: BTNKey | N | null | undefined, iterationType = this.options.iterationType): boolean {
1007
1022
  // TODO there is a bug
1008
1023
  beginRoot = this.ensureNotKey(beginRoot);
1009
1024
  if (!beginRoot) return true;
@@ -1050,7 +1065,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1050
1065
  * expected to be
1051
1066
  * @returns a boolean value.
1052
1067
  */
1053
- isBST(iterationType = this.iterationType): boolean {
1068
+ isBST(iterationType = this.options.iterationType): boolean {
1054
1069
  if (this.root === null) return true;
1055
1070
  return this.isSubtreeBST(this.root, iterationType);
1056
1071
  }
@@ -1097,7 +1112,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1097
1112
  * @param iterationType - The `iterationType` parameter determines the type of traversal to be
1098
1113
  * performed on the subtree. It can have two possible values:
1099
1114
  * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
1100
- * whether or not to include null values in the traversal. If `includeNull` is set to `true`, the
1115
+ * whether to include null values in the traversal. If `includeNull` is set to `true`, the
1101
1116
  * traversal will include null values, otherwise it will skip them.
1102
1117
  * @returns The function `subTreeTraverse` returns an array of values that are the result of invoking
1103
1118
  * the `callback` function on each node in the subtree. The type of the array elements is determined
@@ -1106,7 +1121,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1106
1121
  subTreeTraverse<C extends BTNCallback<N | null | undefined>>(
1107
1122
  callback: C = this._defaultOneParamCallback as C,
1108
1123
  beginRoot: BTNKey | N | null | undefined = this.root,
1109
- iterationType = this.iterationType,
1124
+ iterationType = this.options.iterationType,
1110
1125
  includeNull = false
1111
1126
  ): ReturnType<C>[] {
1112
1127
  beginRoot = this.ensureNotKey(beginRoot);
@@ -1376,7 +1391,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1376
1391
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be
1377
1392
  * performed during the breadth-first search (BFS). It can have two possible values:
1378
1393
  * @param [includeNull=false] - The `includeNull` parameter is a boolean flag that determines whether
1379
- * or not to include null values in the breadth-first search traversal. If `includeNull` is set to
1394
+ * to include null values in the breadth-first search traversal. If `includeNull` is set to
1380
1395
  * `true`, null values will be included in the traversal, otherwise they will be skipped.
1381
1396
  * @returns an array of values that are the result of invoking the callback function on each node in
1382
1397
  * the breadth-first traversal of a binary tree.
@@ -1384,7 +1399,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1384
1399
  bfs<C extends BTNCallback<N | null | undefined>>(
1385
1400
  callback: C = this._defaultOneParamCallback as C,
1386
1401
  beginRoot: BTNKey | N | null | undefined = this.root,
1387
- iterationType = this.iterationType,
1402
+ iterationType = this.options.iterationType,
1388
1403
  includeNull = false
1389
1404
  ): ReturnType<C>[] {
1390
1405
  beginRoot = this.ensureNotKey(beginRoot);
@@ -1477,7 +1492,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1477
1492
  * @param iterationType - The `iterationType` parameter determines the type of iteration to be
1478
1493
  * performed on the tree. It can have two possible values:
1479
1494
  * @param [includeNull=false] - The `includeNull` parameter is a boolean value that determines
1480
- * whether or not to include null values in the resulting levels. If `includeNull` is set to `true`,
1495
+ * whether to include null values in the resulting levels. If `includeNull` is set to `true`,
1481
1496
  * null values will be included in the levels. If `includeNull` is set to `false`, null values will
1482
1497
  * be excluded
1483
1498
  * @returns The function `listLevels` returns a two-dimensional array of type `ReturnType<C>[][]`.
@@ -1485,7 +1500,7 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1485
1500
  listLevels<C extends BTNCallback<N | null | undefined>>(
1486
1501
  callback: C = this._defaultOneParamCallback as C,
1487
1502
  beginRoot: BTNKey | N | null | undefined = this.root,
1488
- iterationType = this.iterationType,
1503
+ iterationType = this.options.iterationType,
1489
1504
  includeNull = false
1490
1505
  ): ReturnType<C>[][] {
1491
1506
  beginRoot = this.ensureNotKey(beginRoot);
@@ -1685,6 +1700,48 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1685
1700
  return ans;
1686
1701
  }
1687
1702
 
1703
+ forEach(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => void): void {
1704
+ for (const entry of this) {
1705
+ callback(entry, this);
1706
+ }
1707
+ }
1708
+
1709
+ filter(predicate: (entry: [BTNKey, V | undefined], tree: typeof this) => boolean) {
1710
+ const newTree = this.createTree();
1711
+ for (const [key, value] of this) {
1712
+ if (predicate([key, value], this)) {
1713
+ newTree.add(key, value);
1714
+ }
1715
+ }
1716
+ return newTree;
1717
+ }
1718
+
1719
+ // TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
1720
+ // map<NV>(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => NV) {
1721
+ // const newTree = this.createTree();
1722
+ // for (const [key, value] of this) {
1723
+ // newTree.add(key, callback([key, value], this));
1724
+ // }
1725
+ // return newTree;
1726
+ // }
1727
+
1728
+ map(callback: (entry: [BTNKey, V | undefined], tree: typeof this) => V) {
1729
+ const newTree = this.createTree();
1730
+ for (const [key, value] of this) {
1731
+ newTree.add(key, callback([key, value], this));
1732
+ }
1733
+ return newTree;
1734
+ }
1735
+
1736
+ reduce<T>(callback: (accumulator: T, entry: [BTNKey, V | undefined], tree: typeof this) => T, initialValue: T): T {
1737
+ let accumulator = initialValue;
1738
+ for (const [key, value] of this) {
1739
+ accumulator = callback(accumulator, [key, value], this);
1740
+ }
1741
+ return accumulator;
1742
+ }
1743
+
1744
+
1688
1745
  /**
1689
1746
  * The above function is an iterator for a binary tree that can be used to traverse the tree in
1690
1747
  * either an iterative or recursive manner.
@@ -1694,32 +1751,32 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1694
1751
  * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
1695
1752
  * binary tree nodes in a specific order.
1696
1753
  */
1697
- * [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1698
- if (!node) {
1699
- return;
1700
- }
1754
+ * [Symbol.iterator](node = this.root): Generator<[BTNKey, V | undefined], void, undefined> {
1755
+ if (!node) return;
1701
1756
 
1702
- if (this.iterationType === IterationType.ITERATIVE) {
1757
+ if (this.options.iterationType === IterationType.ITERATIVE) {
1703
1758
  const stack: (N | null | undefined)[] = [];
1704
1759
  let current: N | null | undefined = node;
1705
1760
 
1706
1761
  while (current || stack.length > 0) {
1707
- while (current) {
1762
+ while (current && !isNaN(current.key)) {
1708
1763
  stack.push(current);
1709
1764
  current = current.left;
1710
1765
  }
1711
1766
 
1712
1767
  current = stack.pop();
1713
1768
 
1714
- if (current) yield current.key;
1715
- if (current) current = current.right;
1769
+ if (current && !isNaN(current.key)) {
1770
+ yield [current.key, current.value];
1771
+ current = current.right;
1772
+ }
1716
1773
  }
1717
1774
  } else {
1718
- if (node.left) {
1775
+ if (node.left && !isNaN(node.key)) {
1719
1776
  yield* this[Symbol.iterator](node.left);
1720
1777
  }
1721
- yield node.key;
1722
- if (node.right) {
1778
+ yield [node.key, node.value];
1779
+ if (node.right && !isNaN(node.key)) {
1723
1780
  yield* this[Symbol.iterator](node.right);
1724
1781
  }
1725
1782
  }
@@ -1727,16 +1784,25 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1727
1784
 
1728
1785
  /**
1729
1786
  * The `print` function is used to display a binary tree structure in a visually appealing way.
1730
- * @param {N | null | undefined} beginRoot - The `root` parameter is of type `BTNKey | N | null |
1787
+ * @param {BTNKey | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `BTNKey | N | null |
1731
1788
  * undefined`. It represents the root node of a binary tree. The root node can have one of the
1732
1789
  * following types:
1790
+ * @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.
1733
1791
  */
1734
- print(beginRoot: BTNKey | N | null | undefined = this.root): void {
1792
+ print(beginRoot: BTNKey | N | null | undefined = this.root, options?: BinaryTreePrintOptions): void {
1793
+ const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1735
1794
  beginRoot = this.ensureNotKey(beginRoot);
1736
1795
  if (!beginRoot) return;
1737
1796
 
1797
+ if (opts.isShowUndefined) console.log(`U for undefined
1798
+ `);
1799
+ if (opts.isShowNull) console.log(`N for null
1800
+ `);
1801
+ if (opts.isShowRedBlackNIL) console.log(`S for Sentinel Node
1802
+ `);
1803
+
1738
1804
  const display = (root: N | null | undefined): void => {
1739
- const [lines, , ,] = this._displayAux(root);
1805
+ const [lines, , ,] = this._displayAux(root, opts);
1740
1806
  for (const line of lines) {
1741
1807
  console.log(line);
1742
1808
  }
@@ -1745,39 +1811,54 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1745
1811
  display(beginRoot);
1746
1812
  }
1747
1813
 
1748
- protected _displayAux(node: N | null | undefined): [string[], number, number, number] {
1749
- if (!node) {
1750
- return [['─'], 1, 0, 0];
1751
- }
1752
-
1753
- const line = node.key.toString();
1754
- const width = line.length;
1814
+ protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
1815
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
1816
+ const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
1755
1817
 
1756
- if (!node.left && !node.right) {
1757
- return [[line], width, 1, Math.floor(width / 2)];
1758
- }
1818
+ // Check if node is null or undefined or key is NaN
1819
+ if (node === null && !isShowNull) {
1820
+ return emptyDisplayLayout;
1821
+ } else if (node === undefined && !isShowUndefined) {
1822
+ return emptyDisplayLayout;
1823
+ } else if (node !== null && node !== undefined && isNaN(node.key) && !isShowRedBlackNIL) {
1824
+ return emptyDisplayLayout;
1825
+ } else if (node !== null && node !== undefined) {
1826
+ // Display logic of normal nodes
1759
1827
 
1760
- const [leftLines, leftWidth, leftHeight, leftMiddle] = node.left ? this._displayAux(node.left) : [[''], 0, 0, 0];
1761
- const [rightLines, rightWidth, rightHeight, rightMiddle] = node.right ? this._displayAux(node.right) : [[''], 0, 0, 0];
1828
+ const key = node.key, line = isNaN(key) ? 'S' : key.toString(), width = line.length;
1762
1829
 
1763
- const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
1764
- + '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
1765
- + line
1766
- + '_'.repeat(Math.max(0, rightMiddle))
1767
- + ' '.repeat(Math.max(0, rightWidth - rightMiddle));
1830
+ return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options))
1768
1831
 
1769
- const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
1770
- + ' '.repeat(width)
1771
- + (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
1832
+ } else {
1833
+ // For cases where none of the conditions are met, null, undefined, and NaN nodes are not displayed
1834
+ const line = node === undefined ? 'U' : 'N', width = line.length;
1772
1835
 
1773
- const mergedLines = [firstLine, secondLine];
1774
- for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
1775
- const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
1776
- const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
1777
- mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
1836
+ return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0])
1778
1837
  }
1779
1838
 
1780
- return [mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
1839
+ function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
1840
+ const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
1841
+ const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
1842
+ const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
1843
+ + '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
1844
+ + line
1845
+ + '_'.repeat(Math.max(0, rightMiddle))
1846
+ + ' '.repeat(Math.max(0, rightWidth - rightMiddle));
1847
+
1848
+ const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
1849
+ + ' '.repeat(width)
1850
+ + (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
1851
+
1852
+ const mergedLines = [firstLine, secondLine];
1853
+
1854
+ for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
1855
+ const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
1856
+ const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
1857
+ mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
1858
+ }
1859
+
1860
+ return <NodeDisplayLayout>[mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
1861
+ }
1781
1862
  }
1782
1863
 
1783
1864
  protected _defaultOneParamCallback = (node: N) => node.key;
@@ -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 { BSTComparator, BSTNodeNested, BSTOptions, BTNCallback, BTNKey } from '../../types';
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';
@@ -62,9 +62,12 @@ export class BSTNode<V = any, N extends BSTNode<V, N> = BSTNodeNested<V>> extend
62
62
  }
63
63
  }
64
64
 
65
- export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>>
66
- extends BinaryTree<V, N>
67
- implements IBinaryTree<V, N> {
65
+ export 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>>>
66
+ extends BinaryTree<V, N, TREE>
67
+ implements IBinaryTree<V, N, TREE> {
68
+
69
+ override options: BSTOptions;
70
+
68
71
  /**
69
72
  * The constructor function initializes a binary search tree with an optional comparator function.
70
73
  * @param {BSTOptions} [options] - An optional object that contains additional configuration options
@@ -72,13 +75,12 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
72
75
  */
73
76
  constructor(options?: BSTOptions) {
74
77
  super(options);
75
- this._root = undefined;
76
- if (options !== undefined) {
77
- const { comparator } = options;
78
- if (comparator !== undefined) {
79
- this._comparator = comparator;
80
- }
78
+ if (options) {
79
+ this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
80
+ } else {
81
+ this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
81
82
  }
83
+ this._root = undefined;
82
84
  }
83
85
 
84
86
  protected override _root?: N;
@@ -102,6 +104,10 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
102
104
  return new BSTNode<V, N>(key, value) as N;
103
105
  }
104
106
 
107
+ override createTree(options?: BSTOptions): TREE {
108
+ return new BST<V, N, TREE>({ ...this.options, ...options }) as TREE;
109
+ }
110
+
105
111
  /**
106
112
  * Time Complexity: O(log n) - Average case for a balanced tree. In the worst case (unbalanced tree), it can be O(n).
107
113
  * Space Complexity: O(1) - Constant space is used.
@@ -215,7 +221,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
215
221
  keysOrNodes: (BTNKey | N | undefined)[],
216
222
  data?: (V | undefined)[],
217
223
  isBalanceAdd = true,
218
- iterationType = this.iterationType
224
+ iterationType = this.options.iterationType
219
225
  ): (N | undefined)[] {
220
226
  // TODO this addMany function is inefficient, it should be optimized
221
227
  function hasNoUndefined(arr: (BTNKey | N | undefined)[]): arr is (BTNKey | N)[] {
@@ -310,7 +316,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
310
316
  * the key of the leftmost node if the comparison result is greater than, and the key of the
311
317
  * rightmost node otherwise. If no node is found, it returns 0.
312
318
  */
313
- lastKey(beginRoot: BTNKey | N | undefined = this.root, iterationType = this.iterationType): BTNKey {
319
+ lastKey(beginRoot: BTNKey | N | undefined = this.root, iterationType = this.options.iterationType): BTNKey {
314
320
  if (this._compare(0, 1) === CP.lt) return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
315
321
  else if (this._compare(0, 1) === CP.gt) return this.getLeftMost(beginRoot, iterationType)?.key ?? 0;
316
322
  else return this.getRightMost(beginRoot, iterationType)?.key ?? 0;
@@ -406,7 +412,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
406
412
  callback: C = this._defaultOneParamCallback as C,
407
413
  onlyOne = false,
408
414
  beginRoot: BTNKey | N | undefined = this.root,
409
- iterationType = this.iterationType
415
+ iterationType = this.options.iterationType
410
416
  ): N[] {
411
417
  beginRoot = this.ensureNotKey(beginRoot);
412
418
  if (!beginRoot) return [];
@@ -487,7 +493,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
487
493
  callback: C = this._defaultOneParamCallback as C,
488
494
  lesserOrGreater: CP = CP.lt,
489
495
  targetNode: BTNKey | N | undefined = this.root,
490
- iterationType = this.iterationType
496
+ iterationType = this.options.iterationType
491
497
  ): ReturnType<C>[] {
492
498
  targetNode = this.ensureNotKey(targetNode);
493
499
  const ans: ReturnType<BTNCallback<N>>[] = [];
@@ -550,7 +556,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
550
556
  * values:
551
557
  * @returns The function `perfectlyBalance` returns a boolean value.
552
558
  */
553
- perfectlyBalance(iterationType = this.iterationType): boolean {
559
+ perfectlyBalance(iterationType = this.options.iterationType): boolean {
554
560
  const sorted = this.dfs(node => node, 'in'),
555
561
  n = sorted.length;
556
562
  this.clear();
@@ -602,7 +608,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
602
608
  * to check if the AVL tree is balanced. It can have two possible values:
603
609
  * @returns a boolean value.
604
610
  */
605
- isAVLBalanced(iterationType = this.iterationType): boolean {
611
+ isAVLBalanced(iterationType = this.options.iterationType): boolean {
606
612
  if (!this.root) return true;
607
613
 
608
614
  let balanced = true;
@@ -646,8 +652,6 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
646
652
  return balanced;
647
653
  }
648
654
 
649
- protected _comparator: BSTComparator = (a, b) => a - b;
650
-
651
655
  protected _setRoot(v: N | undefined) {
652
656
  if (v) {
653
657
  v.parent = undefined;
@@ -664,7 +668,7 @@ export class BST<V = any, N extends BSTNode<V, N> = BSTNode<V, BSTNodeNested<V>>
664
668
  * than), CP.lt (less than), or CP.eq (equal).
665
669
  */
666
670
  protected _compare(a: BTNKey, b: BTNKey): CP {
667
- const compared = this._comparator(a, b);
671
+ const compared = this.options.comparator!(a, b);
668
672
  if (compared > 0) return CP.gt;
669
673
  else if (compared < 0) return CP.lt;
670
674
  else return CP.eq;