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
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
FamilyPosition, NodePredicate,
|
|
14
14
|
OptNode,
|
|
15
15
|
RBTNColor,
|
|
16
|
+
IterationType,
|
|
16
17
|
RedBlackTreeOptions
|
|
17
18
|
} from '../../types';
|
|
18
19
|
import { BST } from './bst';
|
|
@@ -97,16 +98,12 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
97
98
|
*
|
|
98
99
|
* @returns The height.
|
|
99
100
|
*/
|
|
101
|
+
/* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
|
|
100
102
|
get height(): number {
|
|
101
103
|
return this._height;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
* Sets the height of the node.
|
|
106
|
-
* @remarks Time O(1), Space O(1)
|
|
107
|
-
*
|
|
108
|
-
* @param value - The new height.
|
|
109
|
-
*/
|
|
106
|
+
/* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
|
|
110
107
|
set height(value: number) {
|
|
111
108
|
this._height = value;
|
|
112
109
|
}
|
|
@@ -141,20 +138,11 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
141
138
|
*
|
|
142
139
|
* @returns The subtree node count.
|
|
143
140
|
*/
|
|
141
|
+
/* istanbul ignore next -- internal field, exercised indirectly via tree operations */
|
|
144
142
|
get count(): number {
|
|
145
143
|
return this._count;
|
|
146
144
|
}
|
|
147
145
|
|
|
148
|
-
/**
|
|
149
|
-
* Sets the count of nodes in the subtree.
|
|
150
|
-
* @remarks Time O(1), Space O(1)
|
|
151
|
-
*
|
|
152
|
-
* @param value - The new count.
|
|
153
|
-
*/
|
|
154
|
-
set count(value: number) {
|
|
155
|
-
this._count = value;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
146
|
/**
|
|
159
147
|
* Gets the position of the node relative to its parent.
|
|
160
148
|
* @remarks Time O(1), Space O(1)
|
|
@@ -172,6 +160,7 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
172
160
|
return this.left || this.right ? 'ROOT_RIGHT' : 'RIGHT';
|
|
173
161
|
}
|
|
174
162
|
|
|
163
|
+
/* istanbul ignore next -- defensive: unreachable if tree structure is correct */
|
|
175
164
|
return 'MAL_NODE';
|
|
176
165
|
}
|
|
177
166
|
}
|
|
@@ -186,23 +175,6 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
186
175
|
* 2. It is BST itself. Compared with Heap which is not completely ordered, RedBlackTree is completely ordered.
|
|
187
176
|
*
|
|
188
177
|
* @example
|
|
189
|
-
* // basic Red-Black Tree with simple number keys
|
|
190
|
-
* // Create a simple Red-Black Tree with numeric keys
|
|
191
|
-
* const tree = new RedBlackTree([5, 2, 8, 1, 9]);
|
|
192
|
-
*
|
|
193
|
-
* tree.print();
|
|
194
|
-
* // _2___
|
|
195
|
-
* // / \
|
|
196
|
-
* // 1 _8_
|
|
197
|
-
* // / \
|
|
198
|
-
* // 5 9
|
|
199
|
-
*
|
|
200
|
-
* // Verify the tree maintains sorted order
|
|
201
|
-
* console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
|
|
202
|
-
*
|
|
203
|
-
* // Check size
|
|
204
|
-
* console.log(tree.size); // 5;
|
|
205
|
-
* @example
|
|
206
178
|
* // Red-Black Tree with key-value pairs for lookups
|
|
207
179
|
* interface Employee {
|
|
208
180
|
* id: number;
|
|
@@ -368,6 +340,50 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
368
340
|
/**
|
|
369
341
|
* Remove all nodes and clear internal caches.
|
|
370
342
|
* @remarks Time O(n) average, Space O(1)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
* @example
|
|
383
|
+
* // Remove all entries
|
|
384
|
+
* const rbt = new RedBlackTree<number>([1, 2, 3]);
|
|
385
|
+
* rbt.clear();
|
|
386
|
+
* console.log(rbt.isEmpty()); // true;
|
|
371
387
|
*/
|
|
372
388
|
override clear() {
|
|
373
389
|
super.clear();
|
|
@@ -603,10 +619,10 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
603
619
|
if (hMin === NIL || hMax === NIL) {
|
|
604
620
|
this._setMinCache(newNode);
|
|
605
621
|
this._setMaxCache(newNode);
|
|
606
|
-
} else if (parent === hMax && lastCompared > 0) {
|
|
607
|
-
this._setMaxCache(newNode);
|
|
608
|
-
} else if (parent === hMin && lastCompared < 0) {
|
|
609
|
-
this._setMinCache(newNode);
|
|
622
|
+
} else /* istanbul ignore next -- boundary fast-paths at top of _setKVNode intercept boundary inserts before normal path */ if (parent === hMax && lastCompared > 0) {
|
|
623
|
+
/* istanbul ignore next */ this._setMaxCache(newNode);
|
|
624
|
+
} else /* istanbul ignore next */ if (parent === hMin && lastCompared < 0) {
|
|
625
|
+
/* istanbul ignore next */ this._setMinCache(newNode);
|
|
610
626
|
} else {
|
|
611
627
|
if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
612
628
|
if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
@@ -700,6 +716,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
700
716
|
return newNode;
|
|
701
717
|
}
|
|
702
718
|
|
|
719
|
+
/* istanbul ignore next -- structurally unreachable: predecessor never has a right child (it's the max of left subtree) */
|
|
703
720
|
return this._setKVNode(key, value)?.node;
|
|
704
721
|
}
|
|
705
722
|
|
|
@@ -740,6 +757,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
740
757
|
return newNode;
|
|
741
758
|
}
|
|
742
759
|
|
|
760
|
+
/* istanbul ignore next -- structurally unreachable: successor never has a left child (it's the min of right subtree) */
|
|
743
761
|
return this._setKVNode(key, value)?.node;
|
|
744
762
|
}
|
|
745
763
|
|
|
@@ -759,6 +777,63 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
759
777
|
* - updates via a single-pass search (no double walk)
|
|
760
778
|
*
|
|
761
779
|
* @remarks Time O(log n) average, Space O(1)
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
* @example
|
|
821
|
+
* // basic Red-Black Tree with simple number keys
|
|
822
|
+
* // Create a simple Red-Black Tree with numeric keys
|
|
823
|
+
* const tree = new RedBlackTree([5, 2, 8, 1, 9]);
|
|
824
|
+
*
|
|
825
|
+
* tree.print();
|
|
826
|
+
* // _2___
|
|
827
|
+
* // / \
|
|
828
|
+
* // 1 _8_
|
|
829
|
+
* // / \
|
|
830
|
+
* // 5 9
|
|
831
|
+
*
|
|
832
|
+
* // Verify the tree maintains sorted order
|
|
833
|
+
* console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
|
|
834
|
+
*
|
|
835
|
+
* // Check size
|
|
836
|
+
* console.log(tree.size); // 5;
|
|
762
837
|
*/
|
|
763
838
|
override set(
|
|
764
839
|
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -811,6 +886,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
811
886
|
}
|
|
812
887
|
return true;
|
|
813
888
|
}
|
|
889
|
+
/* istanbul ignore next -- defensive: _insert only returns CREATED|UPDATED */
|
|
814
890
|
return false;
|
|
815
891
|
}
|
|
816
892
|
|
|
@@ -819,6 +895,54 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
819
895
|
* @remarks Time O(log n) average, Space O(1)
|
|
820
896
|
* @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
|
|
821
897
|
* @returns Array with deletion metadata (removed node, rebalancing hint if any).
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
* @example
|
|
941
|
+
* // Remove and rebalance
|
|
942
|
+
* const rbt = new RedBlackTree<number>([10, 5, 15, 3, 7]);
|
|
943
|
+
* rbt.delete(5);
|
|
944
|
+
* console.log(rbt.has(5)); // false;
|
|
945
|
+
* console.log(rbt.size); // 4;
|
|
822
946
|
*/
|
|
823
947
|
override delete(
|
|
824
948
|
keyNodeEntryRawOrPredicate: BTNRep<K, V, RedBlackTreeNode<K, V>> | NodePredicate<RedBlackTreeNode<K, V> | null>
|
|
@@ -841,39 +965,38 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
841
965
|
const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : undefined;
|
|
842
966
|
|
|
843
967
|
let originalColor = nodeToDelete.color;
|
|
844
|
-
|
|
968
|
+
const NIL = this.NIL;
|
|
969
|
+
let replacementNode: RedBlackTreeNode<K, V> = NIL;
|
|
845
970
|
|
|
846
971
|
if (!this.isRealNode(nodeToDelete.left)) {
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
}
|
|
972
|
+
// No real left child → replace with right (may be NIL)
|
|
973
|
+
replacementNode = nodeToDelete.right ?? NIL;
|
|
974
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
851
975
|
} else if (!this.isRealNode(nodeToDelete.right)) {
|
|
976
|
+
// No real right child → replace with left
|
|
852
977
|
replacementNode = nodeToDelete.left;
|
|
853
|
-
this._transplant(nodeToDelete,
|
|
978
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
854
979
|
} else {
|
|
980
|
+
// Two children → find in-order successor
|
|
855
981
|
const successor = this.getLeftMost(node => node, nodeToDelete.right);
|
|
856
982
|
if (successor) {
|
|
857
983
|
originalColor = successor.color;
|
|
858
|
-
|
|
984
|
+
replacementNode = successor.right ?? NIL;
|
|
859
985
|
|
|
860
986
|
if (successor.parent === nodeToDelete) {
|
|
861
|
-
if
|
|
862
|
-
|
|
863
|
-
}
|
|
987
|
+
// Even if replacementNode is NIL, set its parent for fixup
|
|
988
|
+
replacementNode.parent = successor;
|
|
864
989
|
} else {
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
}
|
|
869
|
-
if (this.isRealNode(successor.right)) {
|
|
990
|
+
this._transplant(successor, replacementNode);
|
|
991
|
+
successor.right = nodeToDelete.right;
|
|
992
|
+
if (successor.right) {
|
|
870
993
|
successor.right.parent = successor;
|
|
871
994
|
}
|
|
872
995
|
}
|
|
873
996
|
|
|
874
997
|
this._transplant(nodeToDelete, successor);
|
|
875
998
|
successor.left = nodeToDelete.left;
|
|
876
|
-
if (
|
|
999
|
+
if (successor.left) {
|
|
877
1000
|
successor.left.parent = successor;
|
|
878
1001
|
}
|
|
879
1002
|
successor.color = nodeToDelete.color;
|
|
@@ -918,6 +1041,105 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
918
1041
|
* @param [thisArg] - See parameter type for details.
|
|
919
1042
|
* @returns A new RedBlackTree with mapped entries.
|
|
920
1043
|
*/
|
|
1044
|
+
/**
|
|
1045
|
+
* Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
|
|
1046
|
+
* sorted bulk insert, which naturally produces a balanced RBT.
|
|
1047
|
+
* @remarks Time O(N), Space O(N)
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
* @example
|
|
1077
|
+
* // Rebalance tree
|
|
1078
|
+
* const rbt = new RedBlackTree<number>([1, 2, 3, 4, 5]);
|
|
1079
|
+
* rbt.perfectlyBalance();
|
|
1080
|
+
* console.log(rbt.isAVLBalanced()); // true;
|
|
1081
|
+
*/
|
|
1082
|
+
override perfectlyBalance(_iterationType?: IterationType): boolean {
|
|
1083
|
+
// Extract sorted entries, clear, re-insert — RBT self-balances on insert
|
|
1084
|
+
const entries: [K, V | undefined][] = [];
|
|
1085
|
+
for (const [key, value] of this) entries.push([key, value]);
|
|
1086
|
+
if (entries.length <= 1) return true;
|
|
1087
|
+
this.clear();
|
|
1088
|
+
this.setMany(
|
|
1089
|
+
entries.map(([k]) => k),
|
|
1090
|
+
entries.map(([, v]) => v),
|
|
1091
|
+
true // isBalanceAdd
|
|
1092
|
+
);
|
|
1093
|
+
return true;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Transform to new tree
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
* @example
|
|
1138
|
+
* // Transform to new tree
|
|
1139
|
+
* const rbt = new RedBlackTree<number, number>([[1, 10], [2, 20]]);
|
|
1140
|
+
* const doubled = rbt.map((v, k) => [k, (v ?? 0) * 2] as [number, number]);
|
|
1141
|
+
* console.log([...doubled.values()]); // [20, 40];
|
|
1142
|
+
*/
|
|
921
1143
|
override map<MK = K, MV = V, MR = any>(
|
|
922
1144
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
923
1145
|
options?: Partial<RedBlackTreeOptions<MK, MV, MR>>,
|
|
@@ -1131,66 +1353,76 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
1131
1353
|
* @returns void
|
|
1132
1354
|
*/
|
|
1133
1355
|
protected _deleteFixup(node: RedBlackTreeNode<K, V> | undefined): void {
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
return;
|
|
1139
|
-
}
|
|
1356
|
+
// Standard CLRS RB-DELETE-FIXUP: restore black-height invariant.
|
|
1357
|
+
// `node` is the child that replaced the deleted node (may be NIL sentinel).
|
|
1358
|
+
// If RED → just recolor BLACK (trivial fix). If BLACK → double-black repair.
|
|
1359
|
+
if (!node) return;
|
|
1140
1360
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1361
|
+
const NIL = this.NIL;
|
|
1362
|
+
let current: RedBlackTreeNode<K, V> = node;
|
|
1143
1363
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1364
|
+
while (current !== this.root && current.color === 'BLACK') {
|
|
1365
|
+
const parent: RedBlackTreeNode<K, V> | undefined = current.parent;
|
|
1366
|
+
if (!parent) break;
|
|
1147
1367
|
|
|
1148
|
-
|
|
1149
|
-
|
|
1368
|
+
const nodeIsLeft = current === parent.left;
|
|
1369
|
+
let sibling = nodeIsLeft ? parent.right : parent.left;
|
|
1150
1370
|
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1371
|
+
// Case 1: sibling is RED → rotate to get a BLACK sibling
|
|
1372
|
+
if (sibling && sibling.color === 'RED') {
|
|
1373
|
+
sibling.color = 'BLACK';
|
|
1374
|
+
parent.color = 'RED';
|
|
1375
|
+
if (nodeIsLeft) {
|
|
1154
1376
|
this._leftRotate(parent);
|
|
1155
1377
|
sibling = parent.right;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
if ((sibling?.left?.color ?? 'BLACK') === 'BLACK') {
|
|
1159
|
-
if (sibling) sibling.color = 'RED';
|
|
1160
|
-
node = parent;
|
|
1161
1378
|
} else {
|
|
1162
|
-
if (sibling?.left) sibling.left.color = 'BLACK';
|
|
1163
|
-
if (sibling) sibling.color = parent.color;
|
|
1164
|
-
parent.color = 'BLACK';
|
|
1165
1379
|
this._rightRotate(parent);
|
|
1166
|
-
|
|
1380
|
+
sibling = parent.left;
|
|
1167
1381
|
}
|
|
1168
|
-
}
|
|
1169
|
-
let sibling = parent.left;
|
|
1382
|
+
}
|
|
1170
1383
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
if (parent) sibling = parent.left;
|
|
1176
|
-
}
|
|
1384
|
+
const sibLeft = sibling?.left;
|
|
1385
|
+
const sibRight = sibling?.right;
|
|
1386
|
+
const sibLeftBlack = !sibLeft || sibLeft === NIL || sibLeft.color === 'BLACK';
|
|
1387
|
+
const sibRightBlack = !sibRight || sibRight === NIL || sibRight.color === 'BLACK';
|
|
1177
1388
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1389
|
+
if (sibLeftBlack && sibRightBlack) {
|
|
1390
|
+
// Case 2: sibling's children are both BLACK → recolor sibling RED, move up
|
|
1391
|
+
if (sibling) sibling.color = 'RED';
|
|
1392
|
+
current = parent;
|
|
1393
|
+
} else {
|
|
1394
|
+
if (nodeIsLeft) {
|
|
1395
|
+
// Case 3: sibling's right child is BLACK → rotate sibling right first
|
|
1396
|
+
if (sibRightBlack) {
|
|
1397
|
+
if (sibLeft) sibLeft.color = 'BLACK';
|
|
1398
|
+
if (sibling) sibling.color = 'RED';
|
|
1399
|
+
if (sibling) this._rightRotate(sibling);
|
|
1400
|
+
sibling = parent.right;
|
|
1401
|
+
}
|
|
1402
|
+
// Case 4: sibling's right child is RED → final rotation
|
|
1183
1403
|
if (sibling) sibling.color = parent.color;
|
|
1184
|
-
|
|
1404
|
+
parent.color = 'BLACK';
|
|
1405
|
+
if (sibling?.right) sibling.right.color = 'BLACK';
|
|
1185
1406
|
this._leftRotate(parent);
|
|
1186
|
-
|
|
1407
|
+
} else {
|
|
1408
|
+
// Case 3 (mirror): sibling's left child is BLACK → rotate sibling left first
|
|
1409
|
+
if (sibLeftBlack) {
|
|
1410
|
+
if (sibRight) sibRight.color = 'BLACK';
|
|
1411
|
+
if (sibling) sibling.color = 'RED';
|
|
1412
|
+
if (sibling) this._leftRotate(sibling);
|
|
1413
|
+
sibling = parent.left;
|
|
1414
|
+
}
|
|
1415
|
+
// Case 4 (mirror): sibling's left child is RED → final rotation
|
|
1416
|
+
if (sibling) sibling.color = parent.color;
|
|
1417
|
+
parent.color = 'BLACK';
|
|
1418
|
+
if (sibling?.left) sibling.left.color = 'BLACK';
|
|
1419
|
+
this._rightRotate(parent);
|
|
1187
1420
|
}
|
|
1421
|
+
current = this.root!;
|
|
1188
1422
|
}
|
|
1189
1423
|
}
|
|
1190
1424
|
|
|
1191
|
-
|
|
1192
|
-
node.color = 'BLACK';
|
|
1193
|
-
}
|
|
1425
|
+
current.color = 'BLACK';
|
|
1194
1426
|
}
|
|
1195
1427
|
|
|
1196
1428
|
/**
|