data-structure-typed 2.4.4 → 2.5.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 +22 -1
- package/README.md +34 -1
- package/dist/cjs/index.cjs +10639 -2151
- package/dist/cjs-legacy/index.cjs +10694 -2195
- package/dist/esm/index.mjs +10639 -2150
- package/dist/esm-legacy/index.mjs +10694 -2194
- package/dist/types/common/error.d.ts +23 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +128 -51
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +210 -164
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +439 -78
- package/dist/types/data-structures/binary-tree/bst.d.ts +311 -28
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +217 -31
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +218 -152
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +1281 -5
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1087 -201
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +858 -65
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +1133 -5
- package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +220 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +218 -59
- package/dist/types/data-structures/hash/hash-map.d.ts +230 -77
- package/dist/types/data-structures/heap/heap.d.ts +287 -99
- package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
- package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +286 -44
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +278 -65
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +415 -12
- package/dist/types/data-structures/matrix/matrix.d.ts +331 -0
- package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
- package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
- package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
- package/dist/types/data-structures/queue/deque.d.ts +313 -66
- package/dist/types/data-structures/queue/queue.d.ts +211 -42
- package/dist/types/data-structures/stack/stack.d.ts +174 -32
- package/dist/types/data-structures/trie/trie.d.ts +213 -43
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
- package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
- package/dist/umd/data-structure-typed.js +10725 -2221
- package/dist/umd/data-structure-typed.min.js +4 -2
- package/package.json +5 -4
- package/src/common/error.ts +60 -0
- package/src/common/index.ts +2 -0
- package/src/data-structures/base/iterable-element-base.ts +2 -2
- package/src/data-structures/binary-tree/avl-tree.ts +146 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +317 -247
- package/src/data-structures/binary-tree/binary-tree.ts +567 -121
- package/src/data-structures/binary-tree/bst.ts +370 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +328 -96
- package/src/data-structures/binary-tree/segment-tree.ts +378 -248
- package/src/data-structures/binary-tree/tree-map.ts +1411 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1218 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +959 -69
- package/src/data-structures/binary-tree/tree-set.ts +1257 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +233 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +308 -59
- package/src/data-structures/hash/hash-map.ts +254 -79
- package/src/data-structures/heap/heap.ts +305 -102
- package/src/data-structures/heap/max-heap.ts +48 -3
- package/src/data-structures/heap/min-heap.ts +59 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +303 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +293 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +707 -90
- package/src/data-structures/matrix/matrix.ts +433 -22
- package/src/data-structures/priority-queue/max-priority-queue.ts +59 -3
- package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
- package/src/data-structures/priority-queue/priority-queue.ts +60 -0
- package/src/data-structures/queue/deque.ts +358 -68
- package/src/data-structures/queue/queue.ts +223 -42
- package/src/data-structures/stack/stack.ts +184 -32
- package/src/data-structures/trie/trie.ts +227 -44
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
- package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
- package/src/types/data-structures/queue/deque.ts +7 -0
- package/src/utils/utils.ts +4 -2
|
@@ -28,7 +28,7 @@ import { IBinaryTree } from '../../interfaces';
|
|
|
28
28
|
import { isComparable, makeTrampoline, makeTrampolineThunk } from '../../utils';
|
|
29
29
|
import { Queue } from '../queue';
|
|
30
30
|
import { IterableEntryBase } from '../base';
|
|
31
|
-
import { DFSOperation, Range } from '../../common';
|
|
31
|
+
import { DFSOperation, ERR, Range } from '../../common';
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* @template K - The type of the key.
|
|
@@ -205,84 +205,6 @@ export class BinaryTreeNode<K = any, V = any> {
|
|
|
205
205
|
* 5. Leaf Nodes: Nodes without children are leaves.
|
|
206
206
|
*
|
|
207
207
|
* @example
|
|
208
|
-
* // basic BinaryTree creation and insertion
|
|
209
|
-
* // Create a BinaryTree with entries
|
|
210
|
-
* const entries: [number, string][] = [
|
|
211
|
-
* [6, 'six'],
|
|
212
|
-
* [1, 'one'],
|
|
213
|
-
* [2, 'two'],
|
|
214
|
-
* [7, 'seven'],
|
|
215
|
-
* [5, 'five'],
|
|
216
|
-
* [3, 'three'],
|
|
217
|
-
* [4, 'four'],
|
|
218
|
-
* [9, 'nine'],
|
|
219
|
-
* [8, 'eight']
|
|
220
|
-
* ];
|
|
221
|
-
*
|
|
222
|
-
* const tree = new BinaryTree(entries);
|
|
223
|
-
*
|
|
224
|
-
* // Verify size
|
|
225
|
-
* console.log(tree.size); // 9;
|
|
226
|
-
*
|
|
227
|
-
* // Add new element
|
|
228
|
-
* tree.set(10, 'ten');
|
|
229
|
-
* console.log(tree.size); // 10;
|
|
230
|
-
* @example
|
|
231
|
-
* // BinaryTree get and has operations
|
|
232
|
-
* const tree = new BinaryTree(
|
|
233
|
-
* [
|
|
234
|
-
* [5, 'five'],
|
|
235
|
-
* [3, 'three'],
|
|
236
|
-
* [7, 'seven'],
|
|
237
|
-
* [1, 'one'],
|
|
238
|
-
* [4, 'four'],
|
|
239
|
-
* [6, 'six'],
|
|
240
|
-
* [8, 'eight']
|
|
241
|
-
* ],
|
|
242
|
-
* { isMapMode: false }
|
|
243
|
-
* );
|
|
244
|
-
*
|
|
245
|
-
* // Check if key exists
|
|
246
|
-
* console.log(tree.has(5)); // true;
|
|
247
|
-
* console.log(tree.has(10)); // false;
|
|
248
|
-
*
|
|
249
|
-
* // Get value by key
|
|
250
|
-
* console.log(tree.get(3)); // 'three';
|
|
251
|
-
* console.log(tree.get(7)); // 'seven';
|
|
252
|
-
* console.log(tree.get(100)); // undefined;
|
|
253
|
-
*
|
|
254
|
-
* // Get node structure
|
|
255
|
-
* const node = tree.getNode(5);
|
|
256
|
-
* console.log(node?.key); // 5;
|
|
257
|
-
* console.log(node?.value); // 'five';
|
|
258
|
-
* @example
|
|
259
|
-
* // BinaryTree level-order traversal
|
|
260
|
-
* const tree = new BinaryTree([
|
|
261
|
-
* [1, 'one'],
|
|
262
|
-
* [2, 'two'],
|
|
263
|
-
* [3, 'three'],
|
|
264
|
-
* [4, 'four'],
|
|
265
|
-
* [5, 'five'],
|
|
266
|
-
* [6, 'six'],
|
|
267
|
-
* [7, 'seven']
|
|
268
|
-
* ]);
|
|
269
|
-
*
|
|
270
|
-
* // Binary tree maintains level-order insertion
|
|
271
|
-
* // Complete binary tree structure
|
|
272
|
-
* console.log(tree.size); // 7;
|
|
273
|
-
*
|
|
274
|
-
* // Verify all keys are present
|
|
275
|
-
* console.log(tree.has(1)); // true;
|
|
276
|
-
* console.log(tree.has(4)); // true;
|
|
277
|
-
* console.log(tree.has(7)); // true;
|
|
278
|
-
*
|
|
279
|
-
* // Iterate through tree
|
|
280
|
-
* const keys: number[] = [];
|
|
281
|
-
* for (const [key] of tree) {
|
|
282
|
-
* keys.push(key);
|
|
283
|
-
* }
|
|
284
|
-
* console.log(keys.length); // 7;
|
|
285
|
-
* @example
|
|
286
208
|
* // determine loan approval using a decision tree
|
|
287
209
|
* // Decision tree structure
|
|
288
210
|
* const loanDecisionTree = new BinaryTree<string>(
|
|
@@ -371,7 +293,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
371
293
|
if (isMapMode !== undefined) this._isMapMode = isMapMode;
|
|
372
294
|
if (isDuplicate !== undefined) this._isDuplicate = isDuplicate;
|
|
373
295
|
if (typeof toEntryFn === 'function') this._toEntryFn = toEntryFn;
|
|
374
|
-
else if (toEntryFn) throw TypeError('toEntryFn
|
|
296
|
+
else if (toEntryFn) throw new TypeError(ERR.notAFunction('toEntryFn', 'BinaryTree'));
|
|
375
297
|
}
|
|
376
298
|
|
|
377
299
|
if (keysNodesEntriesOrRaws) this.setMany(keysNodesEntriesOrRaws);
|
|
@@ -644,6 +566,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
644
566
|
*
|
|
645
567
|
* @param keyNodeOrEntry - The key, node, or entry to add.
|
|
646
568
|
* @returns True if the addition was successful, false otherwise.
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
* @example
|
|
577
|
+
* // Add a single node
|
|
578
|
+
* const tree = new BinaryTree<number>();
|
|
579
|
+
* tree.add(1);
|
|
580
|
+
* tree.add(2);
|
|
581
|
+
* tree.add(3);
|
|
582
|
+
* console.log(tree.size); // 3;
|
|
583
|
+
* console.log(tree.has(1)); // true;
|
|
647
584
|
*/
|
|
648
585
|
add(
|
|
649
586
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -658,6 +595,41 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
658
595
|
* @param keyNodeOrEntry - The key, node, or entry to set or update.
|
|
659
596
|
* @param [value] - The value, if providing just a key.
|
|
660
597
|
* @returns True if the addition was successful, false otherwise.
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
* @example
|
|
611
|
+
* // basic BinaryTree creation and insertion
|
|
612
|
+
* // Create a BinaryTree with entries
|
|
613
|
+
* const entries: [number, string][] = [
|
|
614
|
+
* [6, 'six'],
|
|
615
|
+
* [1, 'one'],
|
|
616
|
+
* [2, 'two'],
|
|
617
|
+
* [7, 'seven'],
|
|
618
|
+
* [5, 'five'],
|
|
619
|
+
* [3, 'three'],
|
|
620
|
+
* [4, 'four'],
|
|
621
|
+
* [9, 'nine'],
|
|
622
|
+
* [8, 'eight']
|
|
623
|
+
* ];
|
|
624
|
+
*
|
|
625
|
+
* const tree = new BinaryTree(entries);
|
|
626
|
+
*
|
|
627
|
+
* // Verify size
|
|
628
|
+
* console.log(tree.size); // 9;
|
|
629
|
+
*
|
|
630
|
+
* // Add new element
|
|
631
|
+
* tree.set(10, 'ten');
|
|
632
|
+
* console.log(tree.size); // 10;
|
|
661
633
|
*/
|
|
662
634
|
set(
|
|
663
635
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -670,7 +642,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
670
642
|
if (!this._root) {
|
|
671
643
|
this._setRoot(newNode);
|
|
672
644
|
if (this._isMapMode && newNode !== null && newNode !== undefined) this._store.set(newNode.key, newNode);
|
|
673
|
-
this._size = 1;
|
|
645
|
+
if (newNode !== null) this._size = 1;
|
|
674
646
|
return true;
|
|
675
647
|
}
|
|
676
648
|
|
|
@@ -708,7 +680,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
708
680
|
potentialParent.right = newNode;
|
|
709
681
|
}
|
|
710
682
|
if (this._isMapMode && newNode !== null && newNode !== undefined) this._store.set(newNode.key, newNode);
|
|
711
|
-
this._size++;
|
|
683
|
+
if (newNode !== null) this._size++;
|
|
712
684
|
return true;
|
|
713
685
|
}
|
|
714
686
|
|
|
@@ -721,6 +693,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
721
693
|
*
|
|
722
694
|
* @param keysNodesEntriesOrRaws - An iterable of items to set.
|
|
723
695
|
* @returns An array of booleans indicating the success of each individual `set` operation.
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
* @example
|
|
707
|
+
* // Bulk add
|
|
708
|
+
* const tree = new BinaryTree<number>();
|
|
709
|
+
* tree.addMany([1, 2, 3, 4, 5]);
|
|
710
|
+
* console.log(tree.size); // 5;
|
|
724
711
|
*/
|
|
725
712
|
addMany(
|
|
726
713
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -737,6 +724,14 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
737
724
|
* @param keysNodesEntriesOrRaws - An iterable of items to set or update.
|
|
738
725
|
* @param [values] - An optional parallel iterable of values.
|
|
739
726
|
* @returns An array of booleans indicating the success of each individual `set` operation.
|
|
727
|
+
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
* @example
|
|
731
|
+
* // Set multiple entries
|
|
732
|
+
* const tree = new BinaryTree<number, string>();
|
|
733
|
+
* tree.setMany([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
734
|
+
* console.log(tree.size); // 3;
|
|
740
735
|
*/
|
|
741
736
|
setMany(
|
|
742
737
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -772,6 +767,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
772
767
|
* @remarks Time O(N * M), same as `setMany`, where N is the size of `anotherTree` and M is the size of this tree. Space O(M) (from `set`).
|
|
773
768
|
*
|
|
774
769
|
* @param anotherTree - The tree to merge.
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
* @example
|
|
781
|
+
* // Combine trees
|
|
782
|
+
* const t1 = new BinaryTree<number>([1, 2]);
|
|
783
|
+
* const t2 = new BinaryTree<number>([3, 4]);
|
|
784
|
+
* t1.merge(t2);
|
|
785
|
+
* console.log(t1.size); // 4;
|
|
775
786
|
*/
|
|
776
787
|
merge(anotherTree: BinaryTree<K, V, R>) {
|
|
777
788
|
this.setMany(anotherTree, []);
|
|
@@ -800,6 +811,24 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
800
811
|
*
|
|
801
812
|
* @param keyNodeEntryRawOrPredicate - The node to delete.
|
|
802
813
|
* @returns An array containing deletion results (for compatibility with self-balancing trees).
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
* @example
|
|
827
|
+
* // Remove a node
|
|
828
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
829
|
+
* tree.delete(3);
|
|
830
|
+
* console.log(tree.has(3)); // false;
|
|
831
|
+
* console.log(tree.size); // 4;
|
|
803
832
|
*/
|
|
804
833
|
delete(
|
|
805
834
|
keyNodeEntryRawOrPredicate: BTNRep<K, V, BinaryTreeNode<K, V>> | NodePredicate<BinaryTreeNode<K, V> | null>
|
|
@@ -865,6 +894,17 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
865
894
|
return deletedResult;
|
|
866
895
|
}
|
|
867
896
|
|
|
897
|
+
/**
|
|
898
|
+
* Search by predicate
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
* @example
|
|
903
|
+
* // Search by predicate
|
|
904
|
+
* const tree = new BinaryTree<number>([5, 3, 7, 1, 9]);
|
|
905
|
+
* const found = tree.search(n => n!.key > 5, true);
|
|
906
|
+
* console.log(found.length); // >= 1;
|
|
907
|
+
*/
|
|
868
908
|
search(
|
|
869
909
|
keyNodeEntryOrPredicate:
|
|
870
910
|
| K
|
|
@@ -963,6 +1003,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
963
1003
|
* @param [startNode=this._root] - The node to start the search from.
|
|
964
1004
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
965
1005
|
* @returns An array of matching nodes.
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
* @example
|
|
1016
|
+
* // Get nodes by condition
|
|
1017
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1018
|
+
* const nodes = tree.getNodes(node => node.key > 3);
|
|
1019
|
+
* console.log(nodes.length); // 2;
|
|
966
1020
|
*/
|
|
967
1021
|
getNodes(
|
|
968
1022
|
keyNodeEntryOrPredicate:
|
|
@@ -1000,6 +1054,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1000
1054
|
* @param [startNode=this._root] - The node to start the search from.
|
|
1001
1055
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1002
1056
|
* @returns The first matching node, or undefined if not found.
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
* @example
|
|
1068
|
+
* // Get node by key
|
|
1069
|
+
* const tree = new BinaryTree<number, string>([[1, 'root'], [2, 'child']]);
|
|
1070
|
+
* console.log(tree.getNode(2)?.value); // 'child';
|
|
1003
1071
|
*/
|
|
1004
1072
|
getNode(
|
|
1005
1073
|
keyNodeEntryOrPredicate:
|
|
@@ -1030,6 +1098,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1030
1098
|
* @param [startNode=this._root] - The node to start searching from (if not in Map mode).
|
|
1031
1099
|
* @param [iterationType=this.iterationType] - The traversal method (if not in Map mode).
|
|
1032
1100
|
* @returns The associated value, or undefined.
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
* @example
|
|
1114
|
+
* // Retrieve value by key
|
|
1115
|
+
* const tree = new BinaryTree<number, string>([[1, 'root'], [2, 'left'], [3, 'right']]);
|
|
1116
|
+
* console.log(tree.get(2)); // 'left';
|
|
1117
|
+
* console.log(tree.get(99)); // undefined;
|
|
1033
1118
|
*/
|
|
1034
1119
|
override get(
|
|
1035
1120
|
keyNodeEntryOrPredicate: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -1052,6 +1137,46 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1052
1137
|
* @param [startNode] - The node to start the search from.
|
|
1053
1138
|
* @param [iterationType] - The traversal method.
|
|
1054
1139
|
* @returns True if a matching node exists, false otherwise.
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
* @example
|
|
1153
|
+
* // BinaryTree get and has operations
|
|
1154
|
+
* const tree = new BinaryTree(
|
|
1155
|
+
* [
|
|
1156
|
+
* [5, 'five'],
|
|
1157
|
+
* [3, 'three'],
|
|
1158
|
+
* [7, 'seven'],
|
|
1159
|
+
* [1, 'one'],
|
|
1160
|
+
* [4, 'four'],
|
|
1161
|
+
* [6, 'six'],
|
|
1162
|
+
* [8, 'eight']
|
|
1163
|
+
* ],
|
|
1164
|
+
* { isMapMode: false }
|
|
1165
|
+
* );
|
|
1166
|
+
*
|
|
1167
|
+
* // Check if key exists
|
|
1168
|
+
* console.log(tree.has(5)); // true;
|
|
1169
|
+
* console.log(tree.has(10)); // false;
|
|
1170
|
+
*
|
|
1171
|
+
* // Get value by key
|
|
1172
|
+
* console.log(tree.get(3)); // 'three';
|
|
1173
|
+
* console.log(tree.get(7)); // 'seven';
|
|
1174
|
+
* console.log(tree.get(100)); // undefined;
|
|
1175
|
+
*
|
|
1176
|
+
* // Get node structure
|
|
1177
|
+
* const node = tree.getNode(5);
|
|
1178
|
+
* console.log(node?.key); // 5;
|
|
1179
|
+
* console.log(node?.value); // 'five';
|
|
1055
1180
|
*/
|
|
1056
1181
|
override has(
|
|
1057
1182
|
keyNodeEntryOrPredicate?:
|
|
@@ -1089,6 +1214,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1089
1214
|
/**
|
|
1090
1215
|
* Clears the tree of all nodes and values.
|
|
1091
1216
|
* @remarks Time O(N) if in Map mode (due to `_store.clear()`), O(1) otherwise. Space O(1)
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
* @example
|
|
1228
|
+
* // Remove all nodes
|
|
1229
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
1230
|
+
* tree.clear();
|
|
1231
|
+
* console.log(tree.isEmpty()); // true;
|
|
1092
1232
|
*/
|
|
1093
1233
|
clear() {
|
|
1094
1234
|
this._clearNodes();
|
|
@@ -1100,6 +1240,19 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1100
1240
|
* @remarks Time O(1), Space O(1)
|
|
1101
1241
|
*
|
|
1102
1242
|
* @returns True if the tree has no nodes, false otherwise.
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
* @example
|
|
1254
|
+
* // Check empty
|
|
1255
|
+
* console.log(new BinaryTree().isEmpty()); // true;
|
|
1103
1256
|
*/
|
|
1104
1257
|
isEmpty(): boolean {
|
|
1105
1258
|
return this._size === 0;
|
|
@@ -1125,6 +1278,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1125
1278
|
* @param [startNode=this._root] - The node to start checking from.
|
|
1126
1279
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1127
1280
|
* @returns True if it's a valid BST, false otherwise.
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
* @example
|
|
1292
|
+
* // Check BST property
|
|
1293
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
1294
|
+
* // BinaryTree doesn't guarantee BST order
|
|
1295
|
+
* console.log(typeof tree.isBST()); // 'boolean';
|
|
1128
1296
|
*/
|
|
1129
1297
|
isBST(
|
|
1130
1298
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1176,6 +1344,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1176
1344
|
* @param dist - The node to find the depth of.
|
|
1177
1345
|
* @param [startNode=this._root] - The node to measure depth from (defaults to root).
|
|
1178
1346
|
* @returns The depth (0 if `dist` is `startNode`).
|
|
1347
|
+
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
* @example
|
|
1360
|
+
* // Get depth of a node
|
|
1361
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1362
|
+
* const node = tree.getNode(4);
|
|
1363
|
+
* console.log(tree.getDepth(node!)); // 2;
|
|
1179
1364
|
*/
|
|
1180
1365
|
getDepth(
|
|
1181
1366
|
dist: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -1201,6 +1386,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1201
1386
|
* @param [startNode=this._root] - The node to start measuring from.
|
|
1202
1387
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1203
1388
|
* @returns The height ( -1 for an empty tree, 0 for a single-node tree).
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
* @example
|
|
1402
|
+
* // Get tree height
|
|
1403
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1404
|
+
* console.log(tree.getHeight()); // 2;
|
|
1204
1405
|
*/
|
|
1205
1406
|
getHeight(
|
|
1206
1407
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1466,6 +1667,26 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1466
1667
|
return y;
|
|
1467
1668
|
}
|
|
1468
1669
|
|
|
1670
|
+
/**
|
|
1671
|
+
* Depth-first search traversal
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
|
|
1682
|
+
|
|
1683
|
+
|
|
1684
|
+
* @example
|
|
1685
|
+
* // Depth-first search traversal
|
|
1686
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1687
|
+
* const inOrder = tree.dfs(node => node.key, 'IN');
|
|
1688
|
+
* console.log(inOrder); // [4, 2, 5, 1, 3];
|
|
1689
|
+
*/
|
|
1469
1690
|
dfs(): (K | undefined)[];
|
|
1470
1691
|
|
|
1471
1692
|
dfs<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1511,6 +1732,48 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1511
1732
|
return this._dfs(callback, pattern, onlyOne, startNode, iterationType, includeNull);
|
|
1512
1733
|
}
|
|
1513
1734
|
|
|
1735
|
+
/**
|
|
1736
|
+
* BinaryTree level-order traversal
|
|
1737
|
+
|
|
1738
|
+
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
|
|
1748
|
+
|
|
1749
|
+
* @example
|
|
1750
|
+
* // BinaryTree level-order traversal
|
|
1751
|
+
* const tree = new BinaryTree([
|
|
1752
|
+
* [1, 'one'],
|
|
1753
|
+
* [2, 'two'],
|
|
1754
|
+
* [3, 'three'],
|
|
1755
|
+
* [4, 'four'],
|
|
1756
|
+
* [5, 'five'],
|
|
1757
|
+
* [6, 'six'],
|
|
1758
|
+
* [7, 'seven']
|
|
1759
|
+
* ]);
|
|
1760
|
+
*
|
|
1761
|
+
* // Binary tree maintains level-order insertion
|
|
1762
|
+
* // Complete binary tree structure
|
|
1763
|
+
* console.log(tree.size); // 7;
|
|
1764
|
+
*
|
|
1765
|
+
* // Verify all keys are present
|
|
1766
|
+
* console.log(tree.has(1)); // true;
|
|
1767
|
+
* console.log(tree.has(4)); // true;
|
|
1768
|
+
* console.log(tree.has(7)); // true;
|
|
1769
|
+
*
|
|
1770
|
+
* // Iterate through tree
|
|
1771
|
+
* const keys: number[] = [];
|
|
1772
|
+
* for (const [key] of tree) {
|
|
1773
|
+
* keys.push(key);
|
|
1774
|
+
* }
|
|
1775
|
+
* console.log(keys.length); // 7;
|
|
1776
|
+
*/
|
|
1514
1777
|
bfs(): (K | undefined)[];
|
|
1515
1778
|
|
|
1516
1779
|
bfs<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1595,6 +1858,24 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1595
1858
|
return ans;
|
|
1596
1859
|
}
|
|
1597
1860
|
|
|
1861
|
+
/**
|
|
1862
|
+
* Get leaf nodes
|
|
1863
|
+
|
|
1864
|
+
|
|
1865
|
+
|
|
1866
|
+
|
|
1867
|
+
|
|
1868
|
+
|
|
1869
|
+
|
|
1870
|
+
|
|
1871
|
+
|
|
1872
|
+
|
|
1873
|
+
* @example
|
|
1874
|
+
* // Get leaf nodes
|
|
1875
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1876
|
+
* const leafKeys = tree.leaves(node => node.key);
|
|
1877
|
+
* console.log(leafKeys.length); // > 0;
|
|
1878
|
+
*/
|
|
1598
1879
|
leaves(): (K | undefined)[];
|
|
1599
1880
|
|
|
1600
1881
|
leaves<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1605,7 +1886,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1605
1886
|
|
|
1606
1887
|
/**
|
|
1607
1888
|
* Finds all leaf nodes in the tree.
|
|
1608
|
-
* @remarks Time O(N), visits every node. Space O(H) for recursive
|
|
1889
|
+
* @remarks Time O(N), visits every node. Space O(H) for recursive or iterative stack.
|
|
1609
1890
|
*
|
|
1610
1891
|
* @template C - The type of the callback function.
|
|
1611
1892
|
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
|
|
@@ -1636,17 +1917,18 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1636
1917
|
|
|
1637
1918
|
dfs(startNode);
|
|
1638
1919
|
} else {
|
|
1639
|
-
//
|
|
1640
|
-
const
|
|
1920
|
+
// DFS-based (stack) to match recursive order
|
|
1921
|
+
const stack = [startNode];
|
|
1641
1922
|
|
|
1642
|
-
while (
|
|
1643
|
-
const cur =
|
|
1923
|
+
while (stack.length > 0) {
|
|
1924
|
+
const cur = stack.pop()!;
|
|
1644
1925
|
if (this.isRealNode(cur)) {
|
|
1645
1926
|
if (this.isLeaf(cur)) {
|
|
1646
1927
|
leaves.push(callback(cur));
|
|
1647
1928
|
}
|
|
1648
|
-
|
|
1649
|
-
if (this.isRealNode(cur.right))
|
|
1929
|
+
// Push right first so left is processed first (LIFO)
|
|
1930
|
+
if (this.isRealNode(cur.right)) stack.push(cur.right);
|
|
1931
|
+
if (this.isRealNode(cur.left)) stack.push(cur.left);
|
|
1650
1932
|
}
|
|
1651
1933
|
}
|
|
1652
1934
|
}
|
|
@@ -1654,6 +1936,24 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1654
1936
|
return leaves;
|
|
1655
1937
|
}
|
|
1656
1938
|
|
|
1939
|
+
/**
|
|
1940
|
+
* Level-order grouping
|
|
1941
|
+
|
|
1942
|
+
|
|
1943
|
+
|
|
1944
|
+
|
|
1945
|
+
|
|
1946
|
+
|
|
1947
|
+
|
|
1948
|
+
|
|
1949
|
+
|
|
1950
|
+
* @example
|
|
1951
|
+
* // Level-order grouping
|
|
1952
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1953
|
+
* const levels = tree.listLevels(node => node.key);
|
|
1954
|
+
* console.log(levels[0]); // [1];
|
|
1955
|
+
* console.log(levels[1].sort()); // [2, 3];
|
|
1956
|
+
*/
|
|
1657
1957
|
listLevels(): (K | undefined)[][];
|
|
1658
1958
|
|
|
1659
1959
|
listLevels<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1731,6 +2031,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1731
2031
|
return levelsNodes;
|
|
1732
2032
|
}
|
|
1733
2033
|
|
|
2034
|
+
/**
|
|
2035
|
+
* Morris traversal (O(1) space)
|
|
2036
|
+
|
|
2037
|
+
|
|
2038
|
+
|
|
2039
|
+
|
|
2040
|
+
|
|
2041
|
+
|
|
2042
|
+
|
|
2043
|
+
|
|
2044
|
+
|
|
2045
|
+
* @example
|
|
2046
|
+
* // Morris traversal (O(1) space)
|
|
2047
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2048
|
+
* const result = tree.morris(node => node.key, 'IN');
|
|
2049
|
+
* console.log(result.length); // 3;
|
|
2050
|
+
*/
|
|
1734
2051
|
morris(): (K | undefined)[];
|
|
1735
2052
|
|
|
1736
2053
|
morris<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1854,6 +2171,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1854
2171
|
* @remarks Time O(N * M), where N is the number of nodes and M is the tree size during insertion (due to `bfs` + `set`, and `set` is O(M)). Space O(N) for the new tree and the BFS queue.
|
|
1855
2172
|
*
|
|
1856
2173
|
* @returns A new, cloned instance of the tree.
|
|
2174
|
+
|
|
2175
|
+
|
|
2176
|
+
|
|
2177
|
+
|
|
2178
|
+
|
|
2179
|
+
|
|
2180
|
+
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
|
|
2184
|
+
* @example
|
|
2185
|
+
* // Deep copy
|
|
2186
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2187
|
+
* const copy = tree.clone();
|
|
2188
|
+
* copy.delete(1);
|
|
2189
|
+
* console.log(tree.has(1)); // true;
|
|
1857
2190
|
*/
|
|
1858
2191
|
clone(): this {
|
|
1859
2192
|
const out = this._createInstance<K, V, R>();
|
|
@@ -1868,6 +2201,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1868
2201
|
* @param predicate - A function to test each [key, value] pair.
|
|
1869
2202
|
* @param [thisArg] - `this` context for the predicate.
|
|
1870
2203
|
* @returns A new, filtered tree.
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
|
|
2210
|
+
|
|
2211
|
+
|
|
2212
|
+
|
|
2213
|
+
|
|
2214
|
+
* @example
|
|
2215
|
+
* // Filter nodes by condition
|
|
2216
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4]);
|
|
2217
|
+
* const result = tree.filter((_, key) => key > 2);
|
|
2218
|
+
* console.log(result.size); // 2;
|
|
1871
2219
|
*/
|
|
1872
2220
|
filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
|
|
1873
2221
|
const out = this._createInstance<K, V, R>();
|
|
@@ -1887,6 +2235,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1887
2235
|
* @param [options] - Options for the new tree.
|
|
1888
2236
|
* @param [thisArg] - `this` context for the callback.
|
|
1889
2237
|
* @returns A new, mapped tree.
|
|
2238
|
+
|
|
2239
|
+
|
|
2240
|
+
|
|
2241
|
+
|
|
2242
|
+
|
|
2243
|
+
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
|
|
2247
|
+
|
|
2248
|
+
* @example
|
|
2249
|
+
* // Transform to new tree
|
|
2250
|
+
* const tree = new BinaryTree<number, number>([[1, 10], [2, 20]]);
|
|
2251
|
+
* const mapped = tree.map((v, key) => [key, (v ?? 0) + 1] as [number, number]);
|
|
2252
|
+
* console.log([...mapped.values()]); // contains 11;
|
|
1890
2253
|
*/
|
|
1891
2254
|
map<MK = K, MV = V, MR = any>(
|
|
1892
2255
|
cb: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
@@ -1939,6 +2302,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1939
2302
|
*
|
|
1940
2303
|
* @param [options] - Options to control the output.
|
|
1941
2304
|
* @param [startNode=this._root] - The node to start printing from.
|
|
2305
|
+
|
|
2306
|
+
|
|
2307
|
+
|
|
2308
|
+
|
|
2309
|
+
|
|
2310
|
+
|
|
2311
|
+
|
|
2312
|
+
|
|
2313
|
+
|
|
2314
|
+
|
|
2315
|
+
* @example
|
|
2316
|
+
* // Display tree
|
|
2317
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2318
|
+
* expect(() => tree.print()).not.toThrow();
|
|
1942
2319
|
*/
|
|
1943
2320
|
override print(
|
|
1944
2321
|
options?: BinaryTreePrintOptions,
|
|
@@ -2257,41 +2634,60 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
2257
2634
|
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2258
2635
|
options: BinaryTreePrintOptions
|
|
2259
2636
|
): NodeDisplayLayout {
|
|
2260
|
-
const
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
}
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
return _buildNodeDisplay(
|
|
2276
|
-
line,
|
|
2277
|
-
width,
|
|
2278
|
-
this._displayAux(node.left, options),
|
|
2279
|
-
this._displayAux(node.right, options)
|
|
2280
|
-
);
|
|
2281
|
-
} else {
|
|
2282
|
-
// Null or Undefined
|
|
2283
|
-
const line = node === undefined ? 'U' : 'N',
|
|
2284
|
-
width = line.length;
|
|
2637
|
+
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
|
|
2638
|
+
|
|
2639
|
+
// Iterative post-order: compute display layout bottom-up using an explicit stack.
|
|
2640
|
+
// Stages: 0=process left, 1=process right, 2=merge
|
|
2641
|
+
type Frame = {
|
|
2642
|
+
node: BinaryTreeNode<K, V> | null | undefined;
|
|
2643
|
+
stage: 0 | 1 | 2;
|
|
2644
|
+
leftLayout: NodeDisplayLayout;
|
|
2645
|
+
rightLayout: NodeDisplayLayout;
|
|
2646
|
+
};
|
|
2647
|
+
|
|
2648
|
+
const newFrame = (n: BinaryTreeNode<K, V> | null | undefined): Frame => ({
|
|
2649
|
+
node: n, stage: 0, leftLayout: emptyDisplayLayout, rightLayout: emptyDisplayLayout
|
|
2650
|
+
});
|
|
2285
2651
|
|
|
2286
|
-
|
|
2287
|
-
|
|
2652
|
+
const stack: Frame[] = [newFrame(node)];
|
|
2653
|
+
let result: NodeDisplayLayout = emptyDisplayLayout;
|
|
2654
|
+
|
|
2655
|
+
const setChildResult = (layout: NodeDisplayLayout) => {
|
|
2656
|
+
if (stack.length === 0) { result = layout; return; }
|
|
2657
|
+
const parent = stack[stack.length - 1];
|
|
2658
|
+
if (parent.stage === 1) parent.leftLayout = layout;
|
|
2659
|
+
else parent.rightLayout = layout;
|
|
2660
|
+
};
|
|
2661
|
+
|
|
2662
|
+
while (stack.length > 0) {
|
|
2663
|
+
const frame = stack[stack.length - 1];
|
|
2664
|
+
const cur = frame.node;
|
|
2665
|
+
|
|
2666
|
+
if (frame.stage === 0) {
|
|
2667
|
+
// Leaf / empty node — resolve immediately
|
|
2668
|
+
if (this._isDisplayLeaf(cur, options)) {
|
|
2669
|
+
stack.pop();
|
|
2670
|
+
const layout = this._resolveDisplayLeaf(cur, options, emptyDisplayLayout);
|
|
2671
|
+
setChildResult(layout);
|
|
2672
|
+
continue;
|
|
2673
|
+
}
|
|
2674
|
+
frame.stage = 1;
|
|
2675
|
+
stack.push(newFrame(cur!.left));
|
|
2676
|
+
} else if (frame.stage === 1) {
|
|
2677
|
+
frame.stage = 2;
|
|
2678
|
+
stack.push(newFrame(cur!.right));
|
|
2679
|
+
} else {
|
|
2680
|
+
stack.pop();
|
|
2681
|
+
const line = this.isNIL(cur) ? 'S' : String(cur!.key);
|
|
2682
|
+
const layout = BinaryTree._buildNodeDisplay(line, line.length, frame.leftLayout, frame.rightLayout);
|
|
2683
|
+
setChildResult(layout);
|
|
2684
|
+
}
|
|
2288
2685
|
}
|
|
2289
2686
|
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
|
|
2687
|
+
return result;
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
protected static _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
|
|
2295
2691
|
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
|
|
2296
2692
|
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
|
|
2297
2693
|
const firstLine =
|
|
@@ -2324,7 +2720,57 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
2324
2720
|
Math.max(leftHeight, rightHeight) + 2,
|
|
2325
2721
|
leftWidth + Math.floor(width / 2)
|
|
2326
2722
|
];
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
/**
|
|
2726
|
+
* Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf).
|
|
2727
|
+
*/
|
|
2728
|
+
protected _isDisplayLeaf(
|
|
2729
|
+
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2730
|
+
options: BinaryTreePrintOptions
|
|
2731
|
+
): boolean {
|
|
2732
|
+
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
2733
|
+
// Empty/hidden nodes are always leaves
|
|
2734
|
+
if (node === null && !isShowNull) return true;
|
|
2735
|
+
if (node === undefined && !isShowUndefined) return true;
|
|
2736
|
+
if (this.isNIL(node) && !isShowRedBlackNIL) return true;
|
|
2737
|
+
// Shown null/undefined are leaves (no children to recurse into)
|
|
2738
|
+
if (node === null || node === undefined) return true;
|
|
2739
|
+
// Real node: check if it has any children that would be displayed
|
|
2740
|
+
const hasDisplayableLeft = this._hasDisplayableChild(node.left, options);
|
|
2741
|
+
const hasDisplayableRight = this._hasDisplayableChild(node.right, options);
|
|
2742
|
+
return !hasDisplayableLeft && !hasDisplayableRight;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
protected _hasDisplayableChild(
|
|
2746
|
+
child: BinaryTreeNode<K, V> | null | undefined,
|
|
2747
|
+
options: BinaryTreePrintOptions
|
|
2748
|
+
): boolean {
|
|
2749
|
+
if (child === null) return !!options.isShowNull;
|
|
2750
|
+
if (child === undefined) return !!options.isShowUndefined;
|
|
2751
|
+
if (this.isNIL(child)) return !!options.isShowRedBlackNIL;
|
|
2752
|
+
return true; // real node is always displayable
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
/**
|
|
2756
|
+
* Resolve a display leaf node to its layout.
|
|
2757
|
+
*/
|
|
2758
|
+
protected _resolveDisplayLeaf(
|
|
2759
|
+
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2760
|
+
options: BinaryTreePrintOptions,
|
|
2761
|
+
emptyDisplayLayout: NodeDisplayLayout
|
|
2762
|
+
): NodeDisplayLayout {
|
|
2763
|
+
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
2764
|
+
if (node === null && !isShowNull) return emptyDisplayLayout;
|
|
2765
|
+
if (node === undefined && !isShowUndefined) return emptyDisplayLayout;
|
|
2766
|
+
if (this.isNIL(node) && !isShowRedBlackNIL) return emptyDisplayLayout;
|
|
2767
|
+
if (node !== null && node !== undefined) {
|
|
2768
|
+
const line = this.isNIL(node) ? 'S' : String(node.key);
|
|
2769
|
+
return BinaryTree._buildNodeDisplay(line, line.length, emptyDisplayLayout, emptyDisplayLayout);
|
|
2327
2770
|
}
|
|
2771
|
+
// Shown null / undefined
|
|
2772
|
+
const line = node === undefined ? 'U' : 'N';
|
|
2773
|
+
return BinaryTree._buildNodeDisplay(line, line.length, [[''], 1, 0, 0], [[''], 1, 0, 0]);
|
|
2328
2774
|
}
|
|
2329
2775
|
|
|
2330
2776
|
/**
|