deque-typed 1.46.8 → 1.47.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) 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 +51 -13
  4. package/dist/data-structures/binary-tree/binary-tree.js +153 -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/data-structures/hash/hash-map.d.ts +27 -0
  12. package/dist/data-structures/hash/hash-map.js +27 -0
  13. package/dist/interfaces/binary-tree.d.ts +3 -3
  14. package/dist/types/common.d.ts +5 -4
  15. package/dist/types/data-structures/binary-tree/avl-tree.d.ts +2 -1
  16. package/dist/types/data-structures/binary-tree/binary-tree.d.ts +3 -1
  17. package/dist/types/data-structures/binary-tree/binary-tree.js +0 -6
  18. package/dist/types/data-structures/binary-tree/bst.d.ts +2 -1
  19. package/dist/types/data-structures/binary-tree/rb-tree.d.ts +2 -1
  20. package/dist/types/data-structures/binary-tree/tree-multimap.d.ts +2 -1
  21. package/package.json +2 -2
  22. package/src/data-structures/binary-tree/avl-tree.ts +17 -5
  23. package/src/data-structures/binary-tree/binary-tree.ts +175 -62
  24. package/src/data-structures/binary-tree/bst.ts +23 -19
  25. package/src/data-structures/binary-tree/rb-tree.ts +38 -27
  26. package/src/data-structures/binary-tree/tree-multimap.ts +19 -6
  27. package/src/data-structures/hash/hash-map.ts +27 -0
  28. package/src/interfaces/binary-tree.ts +3 -3
  29. package/src/types/common.ts +2 -5
  30. package/src/types/data-structures/binary-tree/avl-tree.ts +5 -1
  31. package/src/types/data-structures/binary-tree/binary-tree.ts +5 -7
  32. package/src/types/data-structures/binary-tree/bst.ts +3 -1
  33. package/src/types/data-structures/binary-tree/rb-tree.ts +3 -1
  34. package/src/types/data-structures/binary-tree/tree-multimap.ts +3 -1
@@ -1,4 +1,5 @@
1
- import { TreeMultimapNode } from '../../../data-structures';
1
+ import { TreeMultimap, TreeMultimapNode } from '../../../data-structures';
2
2
  import { AVLTreeOptions } from './avl-tree';
3
3
  export type TreeMultimapNodeNested<T> = TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, TreeMultimapNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
4
+ export type TreeMultimapNested<T, N extends TreeMultimapNode<T, N>> = TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, TreeMultimap<T, N, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
4
5
  export type TreeMultimapOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeByKey'> & {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deque-typed",
3
- "version": "1.46.8",
3
+ "version": "1.47.2",
4
4
  "description": "Deque. Javascript & Typescript Data Structure.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -119,6 +119,6 @@
119
119
  "typescript": "^4.9.5"
120
120
  },
121
121
  "dependencies": {
122
- "data-structure-typed": "^1.46.7"
122
+ "data-structure-typed": "^1.47.2"
123
123
  }
124
124
  }
@@ -6,8 +6,8 @@
6
6
  * @license MIT License
7
7
  */
8
8
  import { BST, BSTNode } from './bst';
9
- import type { AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey } from '../../types';
10
- import { BTNCallback } from '../../types';
9
+ import type { AVLTreeNested, AVLTreeNodeNested, AVLTreeOptions, BiTreeDeleteResult, BTNKey } from '../../types';
10
+ import { BTNCallback, IterationType } from '../../types';
11
11
  import { IBinaryTree } from '../../interfaces';
12
12
 
13
13
  export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNested<V>> extends BSTNode<V, N> {
@@ -19,9 +19,12 @@ export class AVLTreeNode<V = any, N extends AVLTreeNode<V, N> = AVLTreeNodeNeste
19
19
  }
20
20
  }
21
21
 
22
- export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>>
23
- extends BST<V, N>
24
- implements IBinaryTree<V, N> {
22
+ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTreeNodeNested<V>>, TREE extends AVLTree<V, N, TREE> = AVLTree<V, N, AVLTreeNested<V, N>>>
23
+ extends BST<V, N, TREE>
24
+ implements IBinaryTree<V, N, TREE> {
25
+
26
+ override options: AVLTreeOptions;
27
+
25
28
  /**
26
29
  * This is a constructor function for an AVL tree data structure in TypeScript.
27
30
  * @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
@@ -30,6 +33,11 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
30
33
  */
31
34
  constructor(options?: AVLTreeOptions) {
32
35
  super(options);
36
+ if (options) {
37
+ this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b, ...options }
38
+ } else {
39
+ this.options = { iterationType: IterationType.ITERATIVE, comparator: (a, b) => a - b };
40
+ }
33
41
  }
34
42
 
35
43
  /**
@@ -45,6 +53,10 @@ export class AVLTree<V = any, N extends AVLTreeNode<V, N> = AVLTreeNode<V, AVLTr
45
53
  return new AVLTreeNode<V, N>(key, value) as N;
46
54
  }
47
55
 
56
+ override createTree(options?: AVLTreeOptions): TREE {
57
+ return new AVLTree<V, N, TREE>({ ...this.options, ...options }) as TREE;
58
+ }
59
+
48
60
  /**
49
61
  * Time Complexity: O(log n) - logarithmic time, where "n" is the number of nodes in the tree. The add method of the superclass (BST) has logarithmic time complexity.
50
62
  * Space Complexity: O(1) - constant space, as it doesn't use additional data structures that scale with input size.
@@ -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,80 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1685
1700
  return ans;
1686
1701
  }
1687
1702
 
1703
+ /**
1704
+ * The `forEach` function iterates over each entry in a tree and calls a callback function with the
1705
+ * entry and the tree as arguments.
1706
+ * @param callback - The callback parameter is a function that will be called for each entry in the
1707
+ * tree. It takes two parameters: entry and tree.
1708
+ */
1709
+ forEach(callback: (entry: [BTNKey, V | undefined], tree: this) => void): void {
1710
+ for (const entry of this) {
1711
+ callback(entry, this);
1712
+ }
1713
+ }
1714
+
1715
+ /**
1716
+ * The `filter` function creates a new tree by iterating over the entries of the current tree and
1717
+ * adding the entries that satisfy the given predicate.
1718
+ * @param predicate - The `predicate` parameter is a function that takes two arguments: `entry` and
1719
+ * `tree`.
1720
+ * @returns The `filter` method is returning a new tree object that contains only the entries that
1721
+ * satisfy the given predicate function.
1722
+ */
1723
+ filter(predicate: (entry: [BTNKey, V | undefined], tree: this) => boolean) {
1724
+ const newTree = this.createTree();
1725
+ for (const [key, value] of this) {
1726
+ if (predicate([key, value], this)) {
1727
+ newTree.add(key, value);
1728
+ }
1729
+ }
1730
+ return newTree;
1731
+ }
1732
+
1733
+ // TODO Type error, need to return a TREE<NV> that is a value type only for callback function.
1734
+ // map<NV>(callback: (entry: [BTNKey, V | undefined], tree: this) => NV) {
1735
+ // const newTree = this.createTree();
1736
+ // for (const [key, value] of this) {
1737
+ // newTree.add(key, callback([key, value], this));
1738
+ // }
1739
+ // return newTree;
1740
+ // }
1741
+
1742
+ /**
1743
+ * The `map` function creates a new tree by applying a callback function to each entry in the current
1744
+ * tree.
1745
+ * @param callback - The callback parameter is a function that takes two arguments: entry and tree.
1746
+ * @returns The `map` method is returning a new tree object.
1747
+ */
1748
+ map(callback: (entry: [BTNKey, V | undefined], tree: this) => V) {
1749
+ const newTree = this.createTree();
1750
+ for (const [key, value] of this) {
1751
+ newTree.add(key, callback([key, value], this));
1752
+ }
1753
+ return newTree;
1754
+ }
1755
+
1756
+ /**
1757
+ * The `reduce` function iterates over the entries of a tree and applies a callback function to each
1758
+ * entry, accumulating a single value.
1759
+ * @param callback - The callback parameter is a function that takes three arguments: accumulator,
1760
+ * entry, and tree. It is called for each entry in the tree and is used to accumulate a single value
1761
+ * based on the logic defined in the callback function.
1762
+ * @param {T} initialValue - The initialValue parameter is the initial value of the accumulator. It
1763
+ * is the value that will be passed as the first argument to the callback function when reducing the
1764
+ * elements of the tree.
1765
+ * @returns The `reduce` method is returning the final value of the accumulator after iterating over
1766
+ * all the entries in the tree and applying the callback function to each entry.
1767
+ */
1768
+ reduce<T>(callback: (accumulator: T, entry: [BTNKey, V | undefined], tree: this) => T, initialValue: T): T {
1769
+ let accumulator = initialValue;
1770
+ for (const [key, value] of this) {
1771
+ accumulator = callback(accumulator, [key, value], this);
1772
+ }
1773
+ return accumulator;
1774
+ }
1775
+
1776
+
1688
1777
  /**
1689
1778
  * The above function is an iterator for a binary tree that can be used to traverse the tree in
1690
1779
  * either an iterative or recursive manner.
@@ -1694,32 +1783,32 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1694
1783
  * @returns The `*[Symbol.iterator]` method returns a generator object that yields the keys of the
1695
1784
  * binary tree nodes in a specific order.
1696
1785
  */
1697
- * [Symbol.iterator](node = this.root): Generator<BTNKey, void, undefined> {
1698
- if (!node) {
1699
- return;
1700
- }
1786
+ * [Symbol.iterator](node = this.root): Generator<[BTNKey, V | undefined], void, undefined> {
1787
+ if (!node) return;
1701
1788
 
1702
- if (this.iterationType === IterationType.ITERATIVE) {
1789
+ if (this.options.iterationType === IterationType.ITERATIVE) {
1703
1790
  const stack: (N | null | undefined)[] = [];
1704
1791
  let current: N | null | undefined = node;
1705
1792
 
1706
1793
  while (current || stack.length > 0) {
1707
- while (current) {
1794
+ while (current && !isNaN(current.key)) {
1708
1795
  stack.push(current);
1709
1796
  current = current.left;
1710
1797
  }
1711
1798
 
1712
1799
  current = stack.pop();
1713
1800
 
1714
- if (current) yield current.key;
1715
- if (current) current = current.right;
1801
+ if (current && !isNaN(current.key)) {
1802
+ yield [current.key, current.value];
1803
+ current = current.right;
1804
+ }
1716
1805
  }
1717
1806
  } else {
1718
- if (node.left) {
1807
+ if (node.left && !isNaN(node.key)) {
1719
1808
  yield* this[Symbol.iterator](node.left);
1720
1809
  }
1721
- yield node.key;
1722
- if (node.right) {
1810
+ yield [node.key, node.value];
1811
+ if (node.right && !isNaN(node.key)) {
1723
1812
  yield* this[Symbol.iterator](node.right);
1724
1813
  }
1725
1814
  }
@@ -1727,16 +1816,25 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1727
1816
 
1728
1817
  /**
1729
1818
  * 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 |
1819
+ * @param {BTNKey | N | null | undefined} [beginRoot=this.root] - The `root` parameter is of type `BTNKey | N | null |
1731
1820
  * undefined`. It represents the root node of a binary tree. The root node can have one of the
1732
1821
  * following types:
1822
+ * @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
1823
  */
1734
- print(beginRoot: BTNKey | N | null | undefined = this.root): void {
1824
+ print(beginRoot: BTNKey | N | null | undefined = this.root, options?: BinaryTreePrintOptions): void {
1825
+ const opts = { isShowUndefined: false, isShowNull: false, isShowRedBlackNIL: false, ...options };
1735
1826
  beginRoot = this.ensureNotKey(beginRoot);
1736
1827
  if (!beginRoot) return;
1737
1828
 
1829
+ if (opts.isShowUndefined) console.log(`U for undefined
1830
+ `);
1831
+ if (opts.isShowNull) console.log(`N for null
1832
+ `);
1833
+ if (opts.isShowRedBlackNIL) console.log(`S for Sentinel Node
1834
+ `);
1835
+
1738
1836
  const display = (root: N | null | undefined): void => {
1739
- const [lines, , ,] = this._displayAux(root);
1837
+ const [lines, , ,] = this._displayAux(root, opts);
1740
1838
  for (const line of lines) {
1741
1839
  console.log(line);
1742
1840
  }
@@ -1745,39 +1843,54 @@ export class BinaryTree<V = any, N extends BinaryTreeNode<V, N> = BinaryTreeNode
1745
1843
  display(beginRoot);
1746
1844
  }
1747
1845
 
1748
- protected _displayAux(node: N | null | undefined): [string[], number, number, number] {
1749
- if (!node) {
1750
- return [['─'], 1, 0, 0];
1751
- }
1846
+ protected _displayAux(node: N | null | undefined, options: BinaryTreePrintOptions): NodeDisplayLayout {
1847
+ const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
1848
+ const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
1752
1849
 
1753
- const line = node.key.toString();
1754
- const width = line.length;
1755
-
1756
- if (!node.left && !node.right) {
1757
- return [[line], width, 1, Math.floor(width / 2)];
1758
- }
1850
+ // Check if node is null or undefined or key is NaN
1851
+ if (node === null && !isShowNull) {
1852
+ return emptyDisplayLayout;
1853
+ } else if (node === undefined && !isShowUndefined) {
1854
+ return emptyDisplayLayout;
1855
+ } else if (node !== null && node !== undefined && isNaN(node.key) && !isShowRedBlackNIL) {
1856
+ return emptyDisplayLayout;
1857
+ } else if (node !== null && node !== undefined) {
1858
+ // Display logic of normal nodes
1759
1859
 
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];
1860
+ const key = node.key, line = isNaN(key) ? 'S' : key.toString(), width = line.length;
1762
1861
 
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));
1862
+ return _buildNodeDisplay(line, width, this._displayAux(node.left, options), this._displayAux(node.right, options))
1768
1863
 
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));
1864
+ } else {
1865
+ // For cases where none of the conditions are met, null, undefined, and NaN nodes are not displayed
1866
+ const line = node === undefined ? 'U' : 'N', width = line.length;
1772
1867
 
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);
1868
+ return _buildNodeDisplay(line, width, [[''], 1, 0, 0], [[''], 1, 0, 0])
1778
1869
  }
1779
1870
 
1780
- return [mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
1871
+ function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
1872
+ const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
1873
+ const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
1874
+ const firstLine = ' '.repeat(Math.max(0, leftMiddle + 1))
1875
+ + '_'.repeat(Math.max(0, leftWidth - leftMiddle - 1))
1876
+ + line
1877
+ + '_'.repeat(Math.max(0, rightMiddle))
1878
+ + ' '.repeat(Math.max(0, rightWidth - rightMiddle));
1879
+
1880
+ const secondLine = (leftHeight > 0 ? ' '.repeat(leftMiddle) + '/' + ' '.repeat(leftWidth - leftMiddle - 1) : ' '.repeat(leftWidth))
1881
+ + ' '.repeat(width)
1882
+ + (rightHeight > 0 ? ' '.repeat(rightMiddle) + '\\' + ' '.repeat(rightWidth - rightMiddle - 1) : ' '.repeat(rightWidth));
1883
+
1884
+ const mergedLines = [firstLine, secondLine];
1885
+
1886
+ for (let i = 0; i < Math.max(leftHeight, rightHeight); i++) {
1887
+ const leftLine = i < leftHeight ? leftLines[i] : ' '.repeat(leftWidth);
1888
+ const rightLine = i < rightHeight ? rightLines[i] : ' '.repeat(rightWidth);
1889
+ mergedLines.push(leftLine + ' '.repeat(width) + rightLine);
1890
+ }
1891
+
1892
+ return <NodeDisplayLayout>[mergedLines, leftWidth + width + rightWidth, Math.max(leftHeight, rightHeight) + 2, leftWidth + Math.floor(width / 2)];
1893
+ }
1781
1894
  }
1782
1895
 
1783
1896
  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;