max-priority-queue-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/README.md +63 -0
- package/dist/cjs/index.cjs +403 -98
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +402 -97
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +403 -99
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +402 -98
- package/dist/esm-legacy/index.mjs.map +1 -1
- 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/max-priority-queue-typed.js +400 -95
- package/dist/umd/max-priority-queue-typed.js.map +1 -1
- package/dist/umd/max-priority-queue-typed.min.js +1 -1
- package/dist/umd/max-priority-queue-typed.min.js.map +1 -1
- package/package.json +2 -2
- 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 +134 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +303 -247
- package/src/data-structures/binary-tree/binary-tree.ts +542 -121
- package/src/data-structures/binary-tree/bst.ts +346 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +309 -96
- package/src/data-structures/binary-tree/segment-tree.ts +372 -248
- package/src/data-structures/binary-tree/tree-map.ts +1292 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1098 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +863 -69
- package/src/data-structures/binary-tree/tree-set.ts +1143 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +223 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +299 -59
- package/src/data-structures/hash/hash-map.ts +243 -79
- package/src/data-structures/heap/heap.ts +291 -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 +286 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +278 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +689 -90
- package/src/data-structures/matrix/matrix.ts +425 -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 +343 -68
- package/src/data-structures/queue/queue.ts +211 -42
- package/src/data-structures/stack/stack.ts +174 -32
- package/src/data-structures/trie/trie.ts +215 -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,20 @@ 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
|
+
* @example
|
|
576
|
+
* // Add a single node
|
|
577
|
+
* const tree = new BinaryTree<number>();
|
|
578
|
+
* tree.add(1);
|
|
579
|
+
* tree.add(2);
|
|
580
|
+
* tree.add(3);
|
|
581
|
+
* console.log(tree.size); // 3;
|
|
582
|
+
* console.log(tree.has(1)); // true;
|
|
647
583
|
*/
|
|
648
584
|
add(
|
|
649
585
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined
|
|
@@ -658,6 +594,40 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
658
594
|
* @param keyNodeOrEntry - The key, node, or entry to set or update.
|
|
659
595
|
* @param [value] - The value, if providing just a key.
|
|
660
596
|
* @returns True if the addition was successful, false otherwise.
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
* @example
|
|
609
|
+
* // basic BinaryTree creation and insertion
|
|
610
|
+
* // Create a BinaryTree with entries
|
|
611
|
+
* const entries: [number, string][] = [
|
|
612
|
+
* [6, 'six'],
|
|
613
|
+
* [1, 'one'],
|
|
614
|
+
* [2, 'two'],
|
|
615
|
+
* [7, 'seven'],
|
|
616
|
+
* [5, 'five'],
|
|
617
|
+
* [3, 'three'],
|
|
618
|
+
* [4, 'four'],
|
|
619
|
+
* [9, 'nine'],
|
|
620
|
+
* [8, 'eight']
|
|
621
|
+
* ];
|
|
622
|
+
*
|
|
623
|
+
* const tree = new BinaryTree(entries);
|
|
624
|
+
*
|
|
625
|
+
* // Verify size
|
|
626
|
+
* console.log(tree.size); // 9;
|
|
627
|
+
*
|
|
628
|
+
* // Add new element
|
|
629
|
+
* tree.set(10, 'ten');
|
|
630
|
+
* console.log(tree.size); // 10;
|
|
661
631
|
*/
|
|
662
632
|
set(
|
|
663
633
|
keyNodeOrEntry: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -670,7 +640,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
670
640
|
if (!this._root) {
|
|
671
641
|
this._setRoot(newNode);
|
|
672
642
|
if (this._isMapMode && newNode !== null && newNode !== undefined) this._store.set(newNode.key, newNode);
|
|
673
|
-
this._size = 1;
|
|
643
|
+
if (newNode !== null) this._size = 1;
|
|
674
644
|
return true;
|
|
675
645
|
}
|
|
676
646
|
|
|
@@ -708,7 +678,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
708
678
|
potentialParent.right = newNode;
|
|
709
679
|
}
|
|
710
680
|
if (this._isMapMode && newNode !== null && newNode !== undefined) this._store.set(newNode.key, newNode);
|
|
711
|
-
this._size++;
|
|
681
|
+
if (newNode !== null) this._size++;
|
|
712
682
|
return true;
|
|
713
683
|
}
|
|
714
684
|
|
|
@@ -721,6 +691,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
721
691
|
*
|
|
722
692
|
* @param keysNodesEntriesOrRaws - An iterable of items to set.
|
|
723
693
|
* @returns An array of booleans indicating the success of each individual `set` operation.
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
* @example
|
|
704
|
+
* // Bulk add
|
|
705
|
+
* const tree = new BinaryTree<number>();
|
|
706
|
+
* tree.addMany([1, 2, 3, 4, 5]);
|
|
707
|
+
* console.log(tree.size); // 5;
|
|
724
708
|
*/
|
|
725
709
|
addMany(
|
|
726
710
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -737,6 +721,13 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
737
721
|
* @param keysNodesEntriesOrRaws - An iterable of items to set or update.
|
|
738
722
|
* @param [values] - An optional parallel iterable of values.
|
|
739
723
|
* @returns An array of booleans indicating the success of each individual `set` operation.
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
* @example
|
|
727
|
+
* // Set multiple entries
|
|
728
|
+
* const tree = new BinaryTree<number, string>();
|
|
729
|
+
* tree.setMany([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
730
|
+
* console.log(tree.size); // 3;
|
|
740
731
|
*/
|
|
741
732
|
setMany(
|
|
742
733
|
keysNodesEntriesOrRaws: Iterable<
|
|
@@ -772,6 +763,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
772
763
|
* @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
764
|
*
|
|
774
765
|
* @param anotherTree - The tree to merge.
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
* @example
|
|
776
|
+
* // Combine trees
|
|
777
|
+
* const t1 = new BinaryTree<number>([1, 2]);
|
|
778
|
+
* const t2 = new BinaryTree<number>([3, 4]);
|
|
779
|
+
* t1.merge(t2);
|
|
780
|
+
* console.log(t1.size); // 4;
|
|
775
781
|
*/
|
|
776
782
|
merge(anotherTree: BinaryTree<K, V, R>) {
|
|
777
783
|
this.setMany(anotherTree, []);
|
|
@@ -800,6 +806,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
800
806
|
*
|
|
801
807
|
* @param keyNodeEntryRawOrPredicate - The node to delete.
|
|
802
808
|
* @returns An array containing deletion results (for compatibility with self-balancing trees).
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
* @example
|
|
821
|
+
* // Remove a node
|
|
822
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
823
|
+
* tree.delete(3);
|
|
824
|
+
* console.log(tree.has(3)); // false;
|
|
825
|
+
* console.log(tree.size); // 4;
|
|
803
826
|
*/
|
|
804
827
|
delete(
|
|
805
828
|
keyNodeEntryRawOrPredicate: BTNRep<K, V, BinaryTreeNode<K, V>> | NodePredicate<BinaryTreeNode<K, V> | null>
|
|
@@ -865,6 +888,16 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
865
888
|
return deletedResult;
|
|
866
889
|
}
|
|
867
890
|
|
|
891
|
+
/**
|
|
892
|
+
* Search by predicate
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
* @example
|
|
896
|
+
* // Search by predicate
|
|
897
|
+
* const tree = new BinaryTree<number>([5, 3, 7, 1, 9]);
|
|
898
|
+
* const found = tree.search(n => n!.key > 5, true);
|
|
899
|
+
* console.log(found.length); // >= 1;
|
|
900
|
+
*/
|
|
868
901
|
search(
|
|
869
902
|
keyNodeEntryOrPredicate:
|
|
870
903
|
| K
|
|
@@ -963,6 +996,19 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
963
996
|
* @param [startNode=this._root] - The node to start the search from.
|
|
964
997
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
965
998
|
* @returns An array of matching nodes.
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
* @example
|
|
1008
|
+
* // Get nodes by condition
|
|
1009
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1010
|
+
* const nodes = tree.getNodes(node => node.key > 3);
|
|
1011
|
+
* console.log(nodes.length); // 2;
|
|
966
1012
|
*/
|
|
967
1013
|
getNodes(
|
|
968
1014
|
keyNodeEntryOrPredicate:
|
|
@@ -1000,6 +1046,19 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1000
1046
|
* @param [startNode=this._root] - The node to start the search from.
|
|
1001
1047
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1002
1048
|
* @returns The first matching node, or undefined if not found.
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
* @example
|
|
1059
|
+
* // Get node by key
|
|
1060
|
+
* const tree = new BinaryTree<number, string>([[1, 'root'], [2, 'child']]);
|
|
1061
|
+
* console.log(tree.getNode(2)?.value); // 'child';
|
|
1003
1062
|
*/
|
|
1004
1063
|
getNode(
|
|
1005
1064
|
keyNodeEntryOrPredicate:
|
|
@@ -1030,6 +1089,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1030
1089
|
* @param [startNode=this._root] - The node to start searching from (if not in Map mode).
|
|
1031
1090
|
* @param [iterationType=this.iterationType] - The traversal method (if not in Map mode).
|
|
1032
1091
|
* @returns The associated value, or undefined.
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
* @example
|
|
1104
|
+
* // Retrieve value by key
|
|
1105
|
+
* const tree = new BinaryTree<number, string>([[1, 'root'], [2, 'left'], [3, 'right']]);
|
|
1106
|
+
* console.log(tree.get(2)); // 'left';
|
|
1107
|
+
* console.log(tree.get(99)); // undefined;
|
|
1033
1108
|
*/
|
|
1034
1109
|
override get(
|
|
1035
1110
|
keyNodeEntryOrPredicate: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -1052,6 +1127,45 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1052
1127
|
* @param [startNode] - The node to start the search from.
|
|
1053
1128
|
* @param [iterationType] - The traversal method.
|
|
1054
1129
|
* @returns True if a matching node exists, false otherwise.
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
* @example
|
|
1142
|
+
* // BinaryTree get and has operations
|
|
1143
|
+
* const tree = new BinaryTree(
|
|
1144
|
+
* [
|
|
1145
|
+
* [5, 'five'],
|
|
1146
|
+
* [3, 'three'],
|
|
1147
|
+
* [7, 'seven'],
|
|
1148
|
+
* [1, 'one'],
|
|
1149
|
+
* [4, 'four'],
|
|
1150
|
+
* [6, 'six'],
|
|
1151
|
+
* [8, 'eight']
|
|
1152
|
+
* ],
|
|
1153
|
+
* { isMapMode: false }
|
|
1154
|
+
* );
|
|
1155
|
+
*
|
|
1156
|
+
* // Check if key exists
|
|
1157
|
+
* console.log(tree.has(5)); // true;
|
|
1158
|
+
* console.log(tree.has(10)); // false;
|
|
1159
|
+
*
|
|
1160
|
+
* // Get value by key
|
|
1161
|
+
* console.log(tree.get(3)); // 'three';
|
|
1162
|
+
* console.log(tree.get(7)); // 'seven';
|
|
1163
|
+
* console.log(tree.get(100)); // undefined;
|
|
1164
|
+
*
|
|
1165
|
+
* // Get node structure
|
|
1166
|
+
* const node = tree.getNode(5);
|
|
1167
|
+
* console.log(node?.key); // 5;
|
|
1168
|
+
* console.log(node?.value); // 'five';
|
|
1055
1169
|
*/
|
|
1056
1170
|
override has(
|
|
1057
1171
|
keyNodeEntryOrPredicate?:
|
|
@@ -1089,6 +1203,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1089
1203
|
/**
|
|
1090
1204
|
* Clears the tree of all nodes and values.
|
|
1091
1205
|
* @remarks Time O(N) if in Map mode (due to `_store.clear()`), O(1) otherwise. Space O(1)
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
|
|
1215
|
+
* @example
|
|
1216
|
+
* // Remove all nodes
|
|
1217
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
1218
|
+
* tree.clear();
|
|
1219
|
+
* console.log(tree.isEmpty()); // true;
|
|
1092
1220
|
*/
|
|
1093
1221
|
clear() {
|
|
1094
1222
|
this._clearNodes();
|
|
@@ -1100,6 +1228,18 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1100
1228
|
* @remarks Time O(1), Space O(1)
|
|
1101
1229
|
*
|
|
1102
1230
|
* @returns True if the tree has no nodes, false otherwise.
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
* @example
|
|
1241
|
+
* // Check empty
|
|
1242
|
+
* console.log(new BinaryTree().isEmpty()); // true;
|
|
1103
1243
|
*/
|
|
1104
1244
|
isEmpty(): boolean {
|
|
1105
1245
|
return this._size === 0;
|
|
@@ -1125,6 +1265,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1125
1265
|
* @param [startNode=this._root] - The node to start checking from.
|
|
1126
1266
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1127
1267
|
* @returns True if it's a valid BST, false otherwise.
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
|
|
1273
|
+
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
* @example
|
|
1278
|
+
* // Check BST property
|
|
1279
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
1280
|
+
* // BinaryTree doesn't guarantee BST order
|
|
1281
|
+
* console.log(typeof tree.isBST()); // 'boolean';
|
|
1128
1282
|
*/
|
|
1129
1283
|
isBST(
|
|
1130
1284
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1176,6 +1330,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1176
1330
|
* @param dist - The node to find the depth of.
|
|
1177
1331
|
* @param [startNode=this._root] - The node to measure depth from (defaults to root).
|
|
1178
1332
|
* @returns The depth (0 if `dist` is `startNode`).
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
|
|
1337
|
+
|
|
1338
|
+
|
|
1339
|
+
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
* @example
|
|
1345
|
+
* // Get depth of a node
|
|
1346
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1347
|
+
* const node = tree.getNode(4);
|
|
1348
|
+
* console.log(tree.getDepth(node!)); // 2;
|
|
1179
1349
|
*/
|
|
1180
1350
|
getDepth(
|
|
1181
1351
|
dist: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -1201,6 +1371,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1201
1371
|
* @param [startNode=this._root] - The node to start measuring from.
|
|
1202
1372
|
* @param [iterationType=this.iterationType] - The traversal method.
|
|
1203
1373
|
* @returns The height ( -1 for an empty tree, 0 for a single-node tree).
|
|
1374
|
+
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
|
|
1378
|
+
|
|
1379
|
+
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
* @example
|
|
1386
|
+
* // Get tree height
|
|
1387
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1388
|
+
* console.log(tree.getHeight()); // 2;
|
|
1204
1389
|
*/
|
|
1205
1390
|
getHeight(
|
|
1206
1391
|
startNode: K | BinaryTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined = this._root,
|
|
@@ -1466,6 +1651,25 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1466
1651
|
return y;
|
|
1467
1652
|
}
|
|
1468
1653
|
|
|
1654
|
+
/**
|
|
1655
|
+
* Depth-first search traversal
|
|
1656
|
+
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
|
|
1667
|
+
* @example
|
|
1668
|
+
* // Depth-first search traversal
|
|
1669
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1670
|
+
* const inOrder = tree.dfs(node => node.key, 'IN');
|
|
1671
|
+
* console.log(inOrder); // [4, 2, 5, 1, 3];
|
|
1672
|
+
*/
|
|
1469
1673
|
dfs(): (K | undefined)[];
|
|
1470
1674
|
|
|
1471
1675
|
dfs<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1511,6 +1715,47 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1511
1715
|
return this._dfs(callback, pattern, onlyOne, startNode, iterationType, includeNull);
|
|
1512
1716
|
}
|
|
1513
1717
|
|
|
1718
|
+
/**
|
|
1719
|
+
* BinaryTree level-order traversal
|
|
1720
|
+
|
|
1721
|
+
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
* @example
|
|
1732
|
+
* // BinaryTree level-order traversal
|
|
1733
|
+
* const tree = new BinaryTree([
|
|
1734
|
+
* [1, 'one'],
|
|
1735
|
+
* [2, 'two'],
|
|
1736
|
+
* [3, 'three'],
|
|
1737
|
+
* [4, 'four'],
|
|
1738
|
+
* [5, 'five'],
|
|
1739
|
+
* [6, 'six'],
|
|
1740
|
+
* [7, 'seven']
|
|
1741
|
+
* ]);
|
|
1742
|
+
*
|
|
1743
|
+
* // Binary tree maintains level-order insertion
|
|
1744
|
+
* // Complete binary tree structure
|
|
1745
|
+
* console.log(tree.size); // 7;
|
|
1746
|
+
*
|
|
1747
|
+
* // Verify all keys are present
|
|
1748
|
+
* console.log(tree.has(1)); // true;
|
|
1749
|
+
* console.log(tree.has(4)); // true;
|
|
1750
|
+
* console.log(tree.has(7)); // true;
|
|
1751
|
+
*
|
|
1752
|
+
* // Iterate through tree
|
|
1753
|
+
* const keys: number[] = [];
|
|
1754
|
+
* for (const [key] of tree) {
|
|
1755
|
+
* keys.push(key);
|
|
1756
|
+
* }
|
|
1757
|
+
* console.log(keys.length); // 7;
|
|
1758
|
+
*/
|
|
1514
1759
|
bfs(): (K | undefined)[];
|
|
1515
1760
|
|
|
1516
1761
|
bfs<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1595,6 +1840,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1595
1840
|
return ans;
|
|
1596
1841
|
}
|
|
1597
1842
|
|
|
1843
|
+
/**
|
|
1844
|
+
* Get leaf nodes
|
|
1845
|
+
|
|
1846
|
+
|
|
1847
|
+
|
|
1848
|
+
|
|
1849
|
+
|
|
1850
|
+
|
|
1851
|
+
|
|
1852
|
+
|
|
1853
|
+
|
|
1854
|
+
* @example
|
|
1855
|
+
* // Get leaf nodes
|
|
1856
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1857
|
+
* const leafKeys = tree.leaves(node => node.key);
|
|
1858
|
+
* console.log(leafKeys.length); // > 0;
|
|
1859
|
+
*/
|
|
1598
1860
|
leaves(): (K | undefined)[];
|
|
1599
1861
|
|
|
1600
1862
|
leaves<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1605,7 +1867,7 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1605
1867
|
|
|
1606
1868
|
/**
|
|
1607
1869
|
* Finds all leaf nodes in the tree.
|
|
1608
|
-
* @remarks Time O(N), visits every node. Space O(H) for recursive
|
|
1870
|
+
* @remarks Time O(N), visits every node. Space O(H) for recursive or iterative stack.
|
|
1609
1871
|
*
|
|
1610
1872
|
* @template C - The type of the callback function.
|
|
1611
1873
|
* @param [callback=this._DEFAULT_NODE_CALLBACK] - Function to call on each leaf node.
|
|
@@ -1636,17 +1898,18 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1636
1898
|
|
|
1637
1899
|
dfs(startNode);
|
|
1638
1900
|
} else {
|
|
1639
|
-
//
|
|
1640
|
-
const
|
|
1901
|
+
// DFS-based (stack) to match recursive order
|
|
1902
|
+
const stack = [startNode];
|
|
1641
1903
|
|
|
1642
|
-
while (
|
|
1643
|
-
const cur =
|
|
1904
|
+
while (stack.length > 0) {
|
|
1905
|
+
const cur = stack.pop()!;
|
|
1644
1906
|
if (this.isRealNode(cur)) {
|
|
1645
1907
|
if (this.isLeaf(cur)) {
|
|
1646
1908
|
leaves.push(callback(cur));
|
|
1647
1909
|
}
|
|
1648
|
-
|
|
1649
|
-
if (this.isRealNode(cur.right))
|
|
1910
|
+
// Push right first so left is processed first (LIFO)
|
|
1911
|
+
if (this.isRealNode(cur.right)) stack.push(cur.right);
|
|
1912
|
+
if (this.isRealNode(cur.left)) stack.push(cur.left);
|
|
1650
1913
|
}
|
|
1651
1914
|
}
|
|
1652
1915
|
}
|
|
@@ -1654,6 +1917,23 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1654
1917
|
return leaves;
|
|
1655
1918
|
}
|
|
1656
1919
|
|
|
1920
|
+
/**
|
|
1921
|
+
* Level-order grouping
|
|
1922
|
+
|
|
1923
|
+
|
|
1924
|
+
|
|
1925
|
+
|
|
1926
|
+
|
|
1927
|
+
|
|
1928
|
+
|
|
1929
|
+
|
|
1930
|
+
* @example
|
|
1931
|
+
* // Level-order grouping
|
|
1932
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4, 5]);
|
|
1933
|
+
* const levels = tree.listLevels(node => node.key);
|
|
1934
|
+
* console.log(levels[0]); // [1];
|
|
1935
|
+
* console.log(levels[1].sort()); // [2, 3];
|
|
1936
|
+
*/
|
|
1657
1937
|
listLevels(): (K | undefined)[][];
|
|
1658
1938
|
|
|
1659
1939
|
listLevels<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1731,6 +2011,22 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1731
2011
|
return levelsNodes;
|
|
1732
2012
|
}
|
|
1733
2013
|
|
|
2014
|
+
/**
|
|
2015
|
+
* Morris traversal (O(1) space)
|
|
2016
|
+
|
|
2017
|
+
|
|
2018
|
+
|
|
2019
|
+
|
|
2020
|
+
|
|
2021
|
+
|
|
2022
|
+
|
|
2023
|
+
|
|
2024
|
+
* @example
|
|
2025
|
+
* // Morris traversal (O(1) space)
|
|
2026
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2027
|
+
* const result = tree.morris(node => node.key, 'IN');
|
|
2028
|
+
* console.log(result.length); // 3;
|
|
2029
|
+
*/
|
|
1734
2030
|
morris(): (K | undefined)[];
|
|
1735
2031
|
|
|
1736
2032
|
morris<C extends NodeCallback<BinaryTreeNode<K, V>>>(
|
|
@@ -1854,6 +2150,21 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1854
2150
|
* @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
2151
|
*
|
|
1856
2152
|
* @returns A new, cloned instance of the tree.
|
|
2153
|
+
|
|
2154
|
+
|
|
2155
|
+
|
|
2156
|
+
|
|
2157
|
+
|
|
2158
|
+
|
|
2159
|
+
|
|
2160
|
+
|
|
2161
|
+
|
|
2162
|
+
* @example
|
|
2163
|
+
* // Deep copy
|
|
2164
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2165
|
+
* const copy = tree.clone();
|
|
2166
|
+
* copy.delete(1);
|
|
2167
|
+
* console.log(tree.has(1)); // true;
|
|
1857
2168
|
*/
|
|
1858
2169
|
clone(): this {
|
|
1859
2170
|
const out = this._createInstance<K, V, R>();
|
|
@@ -1868,6 +2179,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1868
2179
|
* @param predicate - A function to test each [key, value] pair.
|
|
1869
2180
|
* @param [thisArg] - `this` context for the predicate.
|
|
1870
2181
|
* @returns A new, filtered tree.
|
|
2182
|
+
|
|
2183
|
+
|
|
2184
|
+
|
|
2185
|
+
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
|
|
2190
|
+
|
|
2191
|
+
* @example
|
|
2192
|
+
* // Filter nodes by condition
|
|
2193
|
+
* const tree = new BinaryTree<number>([1, 2, 3, 4]);
|
|
2194
|
+
* const result = tree.filter((_, key) => key > 2);
|
|
2195
|
+
* console.log(result.size); // 2;
|
|
1871
2196
|
*/
|
|
1872
2197
|
filter(predicate: EntryCallback<K, V | undefined, boolean>, thisArg?: unknown): this {
|
|
1873
2198
|
const out = this._createInstance<K, V, R>();
|
|
@@ -1887,6 +2212,20 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1887
2212
|
* @param [options] - Options for the new tree.
|
|
1888
2213
|
* @param [thisArg] - `this` context for the callback.
|
|
1889
2214
|
* @returns A new, mapped tree.
|
|
2215
|
+
|
|
2216
|
+
|
|
2217
|
+
|
|
2218
|
+
|
|
2219
|
+
|
|
2220
|
+
|
|
2221
|
+
|
|
2222
|
+
|
|
2223
|
+
|
|
2224
|
+
* @example
|
|
2225
|
+
* // Transform to new tree
|
|
2226
|
+
* const tree = new BinaryTree<number, number>([[1, 10], [2, 20]]);
|
|
2227
|
+
* const mapped = tree.map((v, key) => [key, (v ?? 0) + 1] as [number, number]);
|
|
2228
|
+
* console.log([...mapped.values()]); // contains 11;
|
|
1890
2229
|
*/
|
|
1891
2230
|
map<MK = K, MV = V, MR = any>(
|
|
1892
2231
|
cb: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
@@ -1939,6 +2278,19 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
1939
2278
|
*
|
|
1940
2279
|
* @param [options] - Options to control the output.
|
|
1941
2280
|
* @param [startNode=this._root] - The node to start printing from.
|
|
2281
|
+
|
|
2282
|
+
|
|
2283
|
+
|
|
2284
|
+
|
|
2285
|
+
|
|
2286
|
+
|
|
2287
|
+
|
|
2288
|
+
|
|
2289
|
+
|
|
2290
|
+
* @example
|
|
2291
|
+
* // Display tree
|
|
2292
|
+
* const tree = new BinaryTree<number>([1, 2, 3]);
|
|
2293
|
+
* expect(() => tree.print()).not.toThrow();
|
|
1942
2294
|
*/
|
|
1943
2295
|
override print(
|
|
1944
2296
|
options?: BinaryTreePrintOptions,
|
|
@@ -2257,41 +2609,60 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
2257
2609
|
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2258
2610
|
options: BinaryTreePrintOptions
|
|
2259
2611
|
): 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;
|
|
2612
|
+
const emptyDisplayLayout = <NodeDisplayLayout>[['─'], 1, 0, 0];
|
|
2613
|
+
|
|
2614
|
+
// Iterative post-order: compute display layout bottom-up using an explicit stack.
|
|
2615
|
+
// Stages: 0=process left, 1=process right, 2=merge
|
|
2616
|
+
type Frame = {
|
|
2617
|
+
node: BinaryTreeNode<K, V> | null | undefined;
|
|
2618
|
+
stage: 0 | 1 | 2;
|
|
2619
|
+
leftLayout: NodeDisplayLayout;
|
|
2620
|
+
rightLayout: NodeDisplayLayout;
|
|
2621
|
+
};
|
|
2622
|
+
|
|
2623
|
+
const newFrame = (n: BinaryTreeNode<K, V> | null | undefined): Frame => ({
|
|
2624
|
+
node: n, stage: 0, leftLayout: emptyDisplayLayout, rightLayout: emptyDisplayLayout
|
|
2625
|
+
});
|
|
2285
2626
|
|
|
2286
|
-
|
|
2287
|
-
|
|
2627
|
+
const stack: Frame[] = [newFrame(node)];
|
|
2628
|
+
let result: NodeDisplayLayout = emptyDisplayLayout;
|
|
2629
|
+
|
|
2630
|
+
const setChildResult = (layout: NodeDisplayLayout) => {
|
|
2631
|
+
if (stack.length === 0) { result = layout; return; }
|
|
2632
|
+
const parent = stack[stack.length - 1];
|
|
2633
|
+
if (parent.stage === 1) parent.leftLayout = layout;
|
|
2634
|
+
else parent.rightLayout = layout;
|
|
2635
|
+
};
|
|
2636
|
+
|
|
2637
|
+
while (stack.length > 0) {
|
|
2638
|
+
const frame = stack[stack.length - 1];
|
|
2639
|
+
const cur = frame.node;
|
|
2640
|
+
|
|
2641
|
+
if (frame.stage === 0) {
|
|
2642
|
+
// Leaf / empty node — resolve immediately
|
|
2643
|
+
if (this._isDisplayLeaf(cur, options)) {
|
|
2644
|
+
stack.pop();
|
|
2645
|
+
const layout = this._resolveDisplayLeaf(cur, options, emptyDisplayLayout);
|
|
2646
|
+
setChildResult(layout);
|
|
2647
|
+
continue;
|
|
2648
|
+
}
|
|
2649
|
+
frame.stage = 1;
|
|
2650
|
+
stack.push(newFrame(cur!.left));
|
|
2651
|
+
} else if (frame.stage === 1) {
|
|
2652
|
+
frame.stage = 2;
|
|
2653
|
+
stack.push(newFrame(cur!.right));
|
|
2654
|
+
} else {
|
|
2655
|
+
stack.pop();
|
|
2656
|
+
const line = this.isNIL(cur) ? 'S' : String(cur!.key);
|
|
2657
|
+
const layout = BinaryTree._buildNodeDisplay(line, line.length, frame.leftLayout, frame.rightLayout);
|
|
2658
|
+
setChildResult(layout);
|
|
2659
|
+
}
|
|
2288
2660
|
}
|
|
2289
2661
|
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
function _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
|
|
2662
|
+
return result;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
protected static _buildNodeDisplay(line: string, width: number, left: NodeDisplayLayout, right: NodeDisplayLayout) {
|
|
2295
2666
|
const [leftLines, leftWidth, leftHeight, leftMiddle] = left;
|
|
2296
2667
|
const [rightLines, rightWidth, rightHeight, rightMiddle] = right;
|
|
2297
2668
|
const firstLine =
|
|
@@ -2324,7 +2695,57 @@ export class BinaryTree<K = any, V = any, R = any>
|
|
|
2324
2695
|
Math.max(leftHeight, rightHeight) + 2,
|
|
2325
2696
|
leftWidth + Math.floor(width / 2)
|
|
2326
2697
|
];
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
/**
|
|
2701
|
+
* Check if a node is a display leaf (empty, null, undefined, NIL, or real leaf).
|
|
2702
|
+
*/
|
|
2703
|
+
protected _isDisplayLeaf(
|
|
2704
|
+
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2705
|
+
options: BinaryTreePrintOptions
|
|
2706
|
+
): boolean {
|
|
2707
|
+
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
2708
|
+
// Empty/hidden nodes are always leaves
|
|
2709
|
+
if (node === null && !isShowNull) return true;
|
|
2710
|
+
if (node === undefined && !isShowUndefined) return true;
|
|
2711
|
+
if (this.isNIL(node) && !isShowRedBlackNIL) return true;
|
|
2712
|
+
// Shown null/undefined are leaves (no children to recurse into)
|
|
2713
|
+
if (node === null || node === undefined) return true;
|
|
2714
|
+
// Real node: check if it has any children that would be displayed
|
|
2715
|
+
const hasDisplayableLeft = this._hasDisplayableChild(node.left, options);
|
|
2716
|
+
const hasDisplayableRight = this._hasDisplayableChild(node.right, options);
|
|
2717
|
+
return !hasDisplayableLeft && !hasDisplayableRight;
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
protected _hasDisplayableChild(
|
|
2721
|
+
child: BinaryTreeNode<K, V> | null | undefined,
|
|
2722
|
+
options: BinaryTreePrintOptions
|
|
2723
|
+
): boolean {
|
|
2724
|
+
if (child === null) return !!options.isShowNull;
|
|
2725
|
+
if (child === undefined) return !!options.isShowUndefined;
|
|
2726
|
+
if (this.isNIL(child)) return !!options.isShowRedBlackNIL;
|
|
2727
|
+
return true; // real node is always displayable
|
|
2728
|
+
}
|
|
2729
|
+
|
|
2730
|
+
/**
|
|
2731
|
+
* Resolve a display leaf node to its layout.
|
|
2732
|
+
*/
|
|
2733
|
+
protected _resolveDisplayLeaf(
|
|
2734
|
+
node: BinaryTreeNode<K, V> | null | undefined,
|
|
2735
|
+
options: BinaryTreePrintOptions,
|
|
2736
|
+
emptyDisplayLayout: NodeDisplayLayout
|
|
2737
|
+
): NodeDisplayLayout {
|
|
2738
|
+
const { isShowNull, isShowUndefined, isShowRedBlackNIL } = options;
|
|
2739
|
+
if (node === null && !isShowNull) return emptyDisplayLayout;
|
|
2740
|
+
if (node === undefined && !isShowUndefined) return emptyDisplayLayout;
|
|
2741
|
+
if (this.isNIL(node) && !isShowRedBlackNIL) return emptyDisplayLayout;
|
|
2742
|
+
if (node !== null && node !== undefined) {
|
|
2743
|
+
const line = this.isNIL(node) ? 'S' : String(node.key);
|
|
2744
|
+
return BinaryTree._buildNodeDisplay(line, line.length, emptyDisplayLayout, emptyDisplayLayout);
|
|
2327
2745
|
}
|
|
2746
|
+
// Shown null / undefined
|
|
2747
|
+
const line = node === undefined ? 'U' : 'N';
|
|
2748
|
+
return BinaryTree._buildNodeDisplay(line, line.length, [[''], 1, 0, 0], [[''], 1, 0, 0]);
|
|
2328
2749
|
}
|
|
2329
2750
|
|
|
2330
2751
|
/**
|