data-structure-typed 2.4.5 → 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 +1 -1
- package/README.md +15 -5
- package/dist/cjs/index.cjs +10240 -2079
- package/dist/cjs-legacy/index.cjs +10305 -2135
- package/dist/esm/index.mjs +10241 -2078
- package/dist/esm-legacy/index.mjs +10306 -2134
- 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 +429 -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 +212 -32
- 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/directed-graph.d.ts +219 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +204 -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 +272 -65
- 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/umd/data-structure-typed.js +10308 -2133
- package/dist/umd/data-structure-typed.min.js +4 -4
- package/package.json +5 -4
- package/src/data-structures/base/iterable-element-base.ts +4 -5
- package/src/data-structures/binary-tree/avl-tree.ts +146 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +316 -247
- package/src/data-structures/binary-tree/binary-tree.ts +454 -79
- package/src/data-structures/binary-tree/bst.ts +359 -34
- package/src/data-structures/binary-tree/red-black-tree.ts +309 -97
- package/src/data-structures/binary-tree/segment-tree.ts +378 -248
- package/src/data-structures/binary-tree/tree-map.ts +1403 -6
- package/src/data-structures/binary-tree/tree-multi-map.ts +1214 -211
- package/src/data-structures/binary-tree/tree-multi-set.ts +954 -65
- package/src/data-structures/binary-tree/tree-set.ts +1250 -9
- package/src/data-structures/graph/directed-graph.ts +229 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +213 -59
- package/src/data-structures/hash/hash-map.ts +241 -77
- package/src/data-structures/heap/heap.ts +301 -99
- package/src/data-structures/heap/max-heap.ts +46 -0
- 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 +424 -12
- package/src/data-structures/priority-queue/max-priority-queue.ts +57 -0
- 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 +287 -65
- 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 +225 -43
- 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
|
@@ -98,16 +98,12 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
98
98
|
*
|
|
99
99
|
* @returns The height.
|
|
100
100
|
*/
|
|
101
|
+
/* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
|
|
101
102
|
get height(): number {
|
|
102
103
|
return this._height;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
* Sets the height of the node.
|
|
107
|
-
* @remarks Time O(1), Space O(1)
|
|
108
|
-
*
|
|
109
|
-
* @param value - The new height.
|
|
110
|
-
*/
|
|
106
|
+
/* istanbul ignore next -- covered by AVLTree tests (subclass uses height) */
|
|
111
107
|
set height(value: number) {
|
|
112
108
|
this._height = value;
|
|
113
109
|
}
|
|
@@ -142,20 +138,11 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
142
138
|
*
|
|
143
139
|
* @returns The subtree node count.
|
|
144
140
|
*/
|
|
141
|
+
/* istanbul ignore next -- internal field, exercised indirectly via tree operations */
|
|
145
142
|
get count(): number {
|
|
146
143
|
return this._count;
|
|
147
144
|
}
|
|
148
145
|
|
|
149
|
-
/**
|
|
150
|
-
* Sets the count of nodes in the subtree.
|
|
151
|
-
* @remarks Time O(1), Space O(1)
|
|
152
|
-
*
|
|
153
|
-
* @param value - The new count.
|
|
154
|
-
*/
|
|
155
|
-
set count(value: number) {
|
|
156
|
-
this._count = value;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
146
|
/**
|
|
160
147
|
* Gets the position of the node relative to its parent.
|
|
161
148
|
* @remarks Time O(1), Space O(1)
|
|
@@ -173,6 +160,7 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
173
160
|
return this.left || this.right ? 'ROOT_RIGHT' : 'RIGHT';
|
|
174
161
|
}
|
|
175
162
|
|
|
163
|
+
/* istanbul ignore next -- defensive: unreachable if tree structure is correct */
|
|
176
164
|
return 'MAL_NODE';
|
|
177
165
|
}
|
|
178
166
|
}
|
|
@@ -187,23 +175,6 @@ export class RedBlackTreeNode<K = any, V = any> {
|
|
|
187
175
|
* 2. It is BST itself. Compared with Heap which is not completely ordered, RedBlackTree is completely ordered.
|
|
188
176
|
*
|
|
189
177
|
* @example
|
|
190
|
-
* // basic Red-Black Tree with simple number keys
|
|
191
|
-
* // Create a simple Red-Black Tree with numeric keys
|
|
192
|
-
* const tree = new RedBlackTree([5, 2, 8, 1, 9]);
|
|
193
|
-
*
|
|
194
|
-
* tree.print();
|
|
195
|
-
* // _2___
|
|
196
|
-
* // / \
|
|
197
|
-
* // 1 _8_
|
|
198
|
-
* // / \
|
|
199
|
-
* // 5 9
|
|
200
|
-
*
|
|
201
|
-
* // Verify the tree maintains sorted order
|
|
202
|
-
* console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
|
|
203
|
-
*
|
|
204
|
-
* // Check size
|
|
205
|
-
* console.log(tree.size); // 5;
|
|
206
|
-
* @example
|
|
207
178
|
* // Red-Black Tree with key-value pairs for lookups
|
|
208
179
|
* interface Employee {
|
|
209
180
|
* id: number;
|
|
@@ -369,6 +340,50 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
369
340
|
/**
|
|
370
341
|
* Remove all nodes and clear internal caches.
|
|
371
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;
|
|
372
387
|
*/
|
|
373
388
|
override clear() {
|
|
374
389
|
super.clear();
|
|
@@ -604,10 +619,10 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
604
619
|
if (hMin === NIL || hMax === NIL) {
|
|
605
620
|
this._setMinCache(newNode);
|
|
606
621
|
this._setMaxCache(newNode);
|
|
607
|
-
} else if (parent === hMax && lastCompared > 0) {
|
|
608
|
-
this._setMaxCache(newNode);
|
|
609
|
-
} else if (parent === hMin && lastCompared < 0) {
|
|
610
|
-
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);
|
|
611
626
|
} else {
|
|
612
627
|
if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
613
628
|
if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
@@ -701,6 +716,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
701
716
|
return newNode;
|
|
702
717
|
}
|
|
703
718
|
|
|
719
|
+
/* istanbul ignore next -- structurally unreachable: predecessor never has a right child (it's the max of left subtree) */
|
|
704
720
|
return this._setKVNode(key, value)?.node;
|
|
705
721
|
}
|
|
706
722
|
|
|
@@ -741,6 +757,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
741
757
|
return newNode;
|
|
742
758
|
}
|
|
743
759
|
|
|
760
|
+
/* istanbul ignore next -- structurally unreachable: successor never has a left child (it's the min of right subtree) */
|
|
744
761
|
return this._setKVNode(key, value)?.node;
|
|
745
762
|
}
|
|
746
763
|
|
|
@@ -760,6 +777,63 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
760
777
|
* - updates via a single-pass search (no double walk)
|
|
761
778
|
*
|
|
762
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;
|
|
763
837
|
*/
|
|
764
838
|
override set(
|
|
765
839
|
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -812,6 +886,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
812
886
|
}
|
|
813
887
|
return true;
|
|
814
888
|
}
|
|
889
|
+
/* istanbul ignore next -- defensive: _insert only returns CREATED|UPDATED */
|
|
815
890
|
return false;
|
|
816
891
|
}
|
|
817
892
|
|
|
@@ -820,6 +895,54 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
820
895
|
* @remarks Time O(log n) average, Space O(1)
|
|
821
896
|
* @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
|
|
822
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;
|
|
823
946
|
*/
|
|
824
947
|
override delete(
|
|
825
948
|
keyNodeEntryRawOrPredicate: BTNRep<K, V, RedBlackTreeNode<K, V>> | NodePredicate<RedBlackTreeNode<K, V> | null>
|
|
@@ -842,39 +965,38 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
842
965
|
const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : undefined;
|
|
843
966
|
|
|
844
967
|
let originalColor = nodeToDelete.color;
|
|
845
|
-
|
|
968
|
+
const NIL = this.NIL;
|
|
969
|
+
let replacementNode: RedBlackTreeNode<K, V> = NIL;
|
|
846
970
|
|
|
847
971
|
if (!this.isRealNode(nodeToDelete.left)) {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
972
|
+
// No real left child → replace with right (may be NIL)
|
|
973
|
+
replacementNode = nodeToDelete.right ?? NIL;
|
|
974
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
852
975
|
} else if (!this.isRealNode(nodeToDelete.right)) {
|
|
976
|
+
// No real right child → replace with left
|
|
853
977
|
replacementNode = nodeToDelete.left;
|
|
854
|
-
this._transplant(nodeToDelete,
|
|
978
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
855
979
|
} else {
|
|
980
|
+
// Two children → find in-order successor
|
|
856
981
|
const successor = this.getLeftMost(node => node, nodeToDelete.right);
|
|
857
982
|
if (successor) {
|
|
858
983
|
originalColor = successor.color;
|
|
859
|
-
|
|
984
|
+
replacementNode = successor.right ?? NIL;
|
|
860
985
|
|
|
861
986
|
if (successor.parent === nodeToDelete) {
|
|
862
|
-
if
|
|
863
|
-
|
|
864
|
-
}
|
|
987
|
+
// Even if replacementNode is NIL, set its parent for fixup
|
|
988
|
+
replacementNode.parent = successor;
|
|
865
989
|
} else {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
870
|
-
if (this.isRealNode(successor.right)) {
|
|
990
|
+
this._transplant(successor, replacementNode);
|
|
991
|
+
successor.right = nodeToDelete.right;
|
|
992
|
+
if (successor.right) {
|
|
871
993
|
successor.right.parent = successor;
|
|
872
994
|
}
|
|
873
995
|
}
|
|
874
996
|
|
|
875
997
|
this._transplant(nodeToDelete, successor);
|
|
876
998
|
successor.left = nodeToDelete.left;
|
|
877
|
-
if (
|
|
999
|
+
if (successor.left) {
|
|
878
1000
|
successor.left.parent = successor;
|
|
879
1001
|
}
|
|
880
1002
|
successor.color = nodeToDelete.color;
|
|
@@ -923,8 +1045,41 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
923
1045
|
* Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
|
|
924
1046
|
* sorted bulk insert, which naturally produces a balanced RBT.
|
|
925
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;
|
|
926
1081
|
*/
|
|
927
|
-
override perfectlyBalance(
|
|
1082
|
+
override perfectlyBalance(_iterationType?: IterationType): boolean {
|
|
928
1083
|
// Extract sorted entries, clear, re-insert — RBT self-balances on insert
|
|
929
1084
|
const entries: [K, V | undefined][] = [];
|
|
930
1085
|
for (const [key, value] of this) entries.push([key, value]);
|
|
@@ -938,6 +1093,53 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
938
1093
|
return true;
|
|
939
1094
|
}
|
|
940
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
|
+
*/
|
|
941
1143
|
override map<MK = K, MV = V, MR = any>(
|
|
942
1144
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
943
1145
|
options?: Partial<RedBlackTreeOptions<MK, MV, MR>>,
|
|
@@ -1151,66 +1353,76 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
1151
1353
|
* @returns void
|
|
1152
1354
|
*/
|
|
1153
1355
|
protected _deleteFixup(node: RedBlackTreeNode<K, V> | undefined): void {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
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;
|
|
1160
1360
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1361
|
+
const NIL = this.NIL;
|
|
1362
|
+
let current: RedBlackTreeNode<K, V> = node;
|
|
1163
1363
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1364
|
+
while (current !== this.root && current.color === 'BLACK') {
|
|
1365
|
+
const parent: RedBlackTreeNode<K, V> | undefined = current.parent;
|
|
1366
|
+
if (!parent) break;
|
|
1167
1367
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1368
|
+
const nodeIsLeft = current === parent.left;
|
|
1369
|
+
let sibling = nodeIsLeft ? parent.right : parent.left;
|
|
1170
1370
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
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) {
|
|
1174
1376
|
this._leftRotate(parent);
|
|
1175
1377
|
sibling = parent.right;
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
if ((sibling?.left?.color ?? 'BLACK') === 'BLACK') {
|
|
1179
|
-
if (sibling) sibling.color = 'RED';
|
|
1180
|
-
node = parent;
|
|
1181
1378
|
} else {
|
|
1182
|
-
if (sibling?.left) sibling.left.color = 'BLACK';
|
|
1183
|
-
if (sibling) sibling.color = parent.color;
|
|
1184
|
-
parent.color = 'BLACK';
|
|
1185
1379
|
this._rightRotate(parent);
|
|
1186
|
-
|
|
1380
|
+
sibling = parent.left;
|
|
1187
1381
|
}
|
|
1188
|
-
}
|
|
1189
|
-
let sibling = parent.left;
|
|
1382
|
+
}
|
|
1190
1383
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
if (parent) sibling = parent.left;
|
|
1196
|
-
}
|
|
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';
|
|
1197
1388
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
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
|
|
1203
1403
|
if (sibling) sibling.color = parent.color;
|
|
1204
|
-
|
|
1404
|
+
parent.color = 'BLACK';
|
|
1405
|
+
if (sibling?.right) sibling.right.color = 'BLACK';
|
|
1205
1406
|
this._leftRotate(parent);
|
|
1206
|
-
|
|
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);
|
|
1207
1420
|
}
|
|
1421
|
+
current = this.root!;
|
|
1208
1422
|
}
|
|
1209
1423
|
}
|
|
1210
1424
|
|
|
1211
|
-
|
|
1212
|
-
node.color = 'BLACK';
|
|
1213
|
-
}
|
|
1425
|
+
current.color = 'BLACK';
|
|
1214
1426
|
}
|
|
1215
1427
|
|
|
1216
1428
|
/**
|