binary-tree-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/README.md +0 -84
- package/dist/cjs/index.cjs +867 -404
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +864 -401
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +867 -404
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +864 -401
- package/dist/esm-legacy/index.mjs.map +1 -1
- 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/binary-tree-typed.js +860 -397
- package/dist/umd/binary-tree-typed.js.map +1 -1
- package/dist/umd/binary-tree-typed.min.js +2 -2
- package/dist/umd/binary-tree-typed.min.js.map +1 -1
- package/package.json +2 -2
- package/src/data-structures/base/iterable-element-base.ts +4 -5
- package/src/data-structures/binary-tree/avl-tree.ts +134 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +302 -247
- package/src/data-structures/binary-tree/binary-tree.ts +429 -79
- package/src/data-structures/binary-tree/bst.ts +335 -34
- package/src/data-structures/binary-tree/red-black-tree.ts +290 -97
- package/src/data-structures/binary-tree/segment-tree.ts +372 -248
- package/src/data-structures/binary-tree/tree-map.ts +1284 -6
- package/src/data-structures/binary-tree/tree-multi-map.ts +1094 -211
- package/src/data-structures/binary-tree/tree-multi-set.ts +858 -65
- package/src/data-structures/binary-tree/tree-set.ts +1136 -9
- package/src/data-structures/graph/directed-graph.ts +219 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +204 -59
- package/src/data-structures/hash/hash-map.ts +230 -77
- package/src/data-structures/heap/heap.ts +287 -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 +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 +416 -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 +272 -65
- 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 +213 -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,46 @@ 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
|
+
* @example
|
|
379
|
+
* // Remove all entries
|
|
380
|
+
* const rbt = new RedBlackTree<number>([1, 2, 3]);
|
|
381
|
+
* rbt.clear();
|
|
382
|
+
* console.log(rbt.isEmpty()); // true;
|
|
372
383
|
*/
|
|
373
384
|
override clear() {
|
|
374
385
|
super.clear();
|
|
@@ -604,10 +615,10 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
604
615
|
if (hMin === NIL || hMax === NIL) {
|
|
605
616
|
this._setMinCache(newNode);
|
|
606
617
|
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);
|
|
618
|
+
} else /* istanbul ignore next -- boundary fast-paths at top of _setKVNode intercept boundary inserts before normal path */ if (parent === hMax && lastCompared > 0) {
|
|
619
|
+
/* istanbul ignore next */ this._setMaxCache(newNode);
|
|
620
|
+
} else /* istanbul ignore next */ if (parent === hMin && lastCompared < 0) {
|
|
621
|
+
/* istanbul ignore next */ this._setMinCache(newNode);
|
|
611
622
|
} else {
|
|
612
623
|
if (cmp(newNode.key, hMin.key) < 0) this._setMinCache(newNode);
|
|
613
624
|
if (cmp(newNode.key, hMax.key) > 0) this._setMaxCache(newNode);
|
|
@@ -701,6 +712,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
701
712
|
return newNode;
|
|
702
713
|
}
|
|
703
714
|
|
|
715
|
+
/* istanbul ignore next -- structurally unreachable: predecessor never has a right child (it's the max of left subtree) */
|
|
704
716
|
return this._setKVNode(key, value)?.node;
|
|
705
717
|
}
|
|
706
718
|
|
|
@@ -741,6 +753,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
741
753
|
return newNode;
|
|
742
754
|
}
|
|
743
755
|
|
|
756
|
+
/* istanbul ignore next -- structurally unreachable: successor never has a left child (it's the min of right subtree) */
|
|
744
757
|
return this._setKVNode(key, value)?.node;
|
|
745
758
|
}
|
|
746
759
|
|
|
@@ -760,6 +773,59 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
760
773
|
* - updates via a single-pass search (no double walk)
|
|
761
774
|
*
|
|
762
775
|
* @remarks Time O(log n) average, Space O(1)
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
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
|
+
* @example
|
|
813
|
+
* // basic Red-Black Tree with simple number keys
|
|
814
|
+
* // Create a simple Red-Black Tree with numeric keys
|
|
815
|
+
* const tree = new RedBlackTree([5, 2, 8, 1, 9]);
|
|
816
|
+
*
|
|
817
|
+
* tree.print();
|
|
818
|
+
* // _2___
|
|
819
|
+
* // / \
|
|
820
|
+
* // 1 _8_
|
|
821
|
+
* // / \
|
|
822
|
+
* // 5 9
|
|
823
|
+
*
|
|
824
|
+
* // Verify the tree maintains sorted order
|
|
825
|
+
* console.log([...tree.keys()]); // [1, 2, 5, 8, 9];
|
|
826
|
+
*
|
|
827
|
+
* // Check size
|
|
828
|
+
* console.log(tree.size); // 5;
|
|
763
829
|
*/
|
|
764
830
|
override set(
|
|
765
831
|
keyNodeOrEntry: K | RedBlackTreeNode<K, V> | [K | null | undefined, V | undefined] | null | undefined,
|
|
@@ -812,6 +878,7 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
812
878
|
}
|
|
813
879
|
return true;
|
|
814
880
|
}
|
|
881
|
+
/* istanbul ignore next -- defensive: _insert only returns CREATED|UPDATED */
|
|
815
882
|
return false;
|
|
816
883
|
}
|
|
817
884
|
|
|
@@ -820,6 +887,50 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
820
887
|
* @remarks Time O(log n) average, Space O(1)
|
|
821
888
|
* @param keyNodeEntryRawOrPredicate - Key, node, or [key, value] entry identifying the node to delete.
|
|
822
889
|
* @returns Array with deletion metadata (removed node, rebalancing hint if any).
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
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
|
+
* @example
|
|
929
|
+
* // Remove and rebalance
|
|
930
|
+
* const rbt = new RedBlackTree<number>([10, 5, 15, 3, 7]);
|
|
931
|
+
* rbt.delete(5);
|
|
932
|
+
* console.log(rbt.has(5)); // false;
|
|
933
|
+
* console.log(rbt.size); // 4;
|
|
823
934
|
*/
|
|
824
935
|
override delete(
|
|
825
936
|
keyNodeEntryRawOrPredicate: BTNRep<K, V, RedBlackTreeNode<K, V>> | NodePredicate<RedBlackTreeNode<K, V> | null>
|
|
@@ -842,39 +953,38 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
842
953
|
const nextMax = willDeleteMax ? this._predecessorOf(nodeToDelete) : undefined;
|
|
843
954
|
|
|
844
955
|
let originalColor = nodeToDelete.color;
|
|
845
|
-
|
|
956
|
+
const NIL = this.NIL;
|
|
957
|
+
let replacementNode: RedBlackTreeNode<K, V> = NIL;
|
|
846
958
|
|
|
847
959
|
if (!this.isRealNode(nodeToDelete.left)) {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
}
|
|
960
|
+
// No real left child → replace with right (may be NIL)
|
|
961
|
+
replacementNode = nodeToDelete.right ?? NIL;
|
|
962
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
852
963
|
} else if (!this.isRealNode(nodeToDelete.right)) {
|
|
964
|
+
// No real right child → replace with left
|
|
853
965
|
replacementNode = nodeToDelete.left;
|
|
854
|
-
this._transplant(nodeToDelete,
|
|
966
|
+
this._transplant(nodeToDelete, replacementNode);
|
|
855
967
|
} else {
|
|
968
|
+
// Two children → find in-order successor
|
|
856
969
|
const successor = this.getLeftMost(node => node, nodeToDelete.right);
|
|
857
970
|
if (successor) {
|
|
858
971
|
originalColor = successor.color;
|
|
859
|
-
|
|
972
|
+
replacementNode = successor.right ?? NIL;
|
|
860
973
|
|
|
861
974
|
if (successor.parent === nodeToDelete) {
|
|
862
|
-
if
|
|
863
|
-
|
|
864
|
-
}
|
|
975
|
+
// Even if replacementNode is NIL, set its parent for fixup
|
|
976
|
+
replacementNode.parent = successor;
|
|
865
977
|
} else {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
}
|
|
870
|
-
if (this.isRealNode(successor.right)) {
|
|
978
|
+
this._transplant(successor, replacementNode);
|
|
979
|
+
successor.right = nodeToDelete.right;
|
|
980
|
+
if (successor.right) {
|
|
871
981
|
successor.right.parent = successor;
|
|
872
982
|
}
|
|
873
983
|
}
|
|
874
984
|
|
|
875
985
|
this._transplant(nodeToDelete, successor);
|
|
876
986
|
successor.left = nodeToDelete.left;
|
|
877
|
-
if (
|
|
987
|
+
if (successor.left) {
|
|
878
988
|
successor.left.parent = successor;
|
|
879
989
|
}
|
|
880
990
|
successor.color = nodeToDelete.color;
|
|
@@ -923,8 +1033,38 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
923
1033
|
* Red-Black trees are self-balancing — `perfectlyBalance` rebuilds via
|
|
924
1034
|
* sorted bulk insert, which naturally produces a balanced RBT.
|
|
925
1035
|
* @remarks Time O(N), Space O(N)
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
* @example
|
|
1062
|
+
* // Rebalance tree
|
|
1063
|
+
* const rbt = new RedBlackTree<number>([1, 2, 3, 4, 5]);
|
|
1064
|
+
* rbt.perfectlyBalance();
|
|
1065
|
+
* console.log(rbt.isAVLBalanced()); // true;
|
|
926
1066
|
*/
|
|
927
|
-
override perfectlyBalance(
|
|
1067
|
+
override perfectlyBalance(_iterationType?: IterationType): boolean {
|
|
928
1068
|
// Extract sorted entries, clear, re-insert — RBT self-balances on insert
|
|
929
1069
|
const entries: [K, V | undefined][] = [];
|
|
930
1070
|
for (const [key, value] of this) entries.push([key, value]);
|
|
@@ -938,6 +1078,49 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
938
1078
|
return true;
|
|
939
1079
|
}
|
|
940
1080
|
|
|
1081
|
+
/**
|
|
1082
|
+
* Transform to new tree
|
|
1083
|
+
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
* @example
|
|
1119
|
+
* // Transform to new tree
|
|
1120
|
+
* const rbt = new RedBlackTree<number, number>([[1, 10], [2, 20]]);
|
|
1121
|
+
* const doubled = rbt.map((v, k) => [k, (v ?? 0) * 2] as [number, number]);
|
|
1122
|
+
* console.log([...doubled.values()]); // [20, 40];
|
|
1123
|
+
*/
|
|
941
1124
|
override map<MK = K, MV = V, MR = any>(
|
|
942
1125
|
callback: EntryCallback<K, V | undefined, [MK, MV]>,
|
|
943
1126
|
options?: Partial<RedBlackTreeOptions<MK, MV, MR>>,
|
|
@@ -1151,66 +1334,76 @@ export class RedBlackTree<K = any, V = any, R = any> extends BST<K, V, R> implem
|
|
|
1151
1334
|
* @returns void
|
|
1152
1335
|
*/
|
|
1153
1336
|
protected _deleteFixup(node: RedBlackTreeNode<K, V> | undefined): void {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1337
|
+
// Standard CLRS RB-DELETE-FIXUP: restore black-height invariant.
|
|
1338
|
+
// `node` is the child that replaced the deleted node (may be NIL sentinel).
|
|
1339
|
+
// If RED → just recolor BLACK (trivial fix). If BLACK → double-black repair.
|
|
1340
|
+
if (!node) return;
|
|
1160
1341
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1342
|
+
const NIL = this.NIL;
|
|
1343
|
+
let current: RedBlackTreeNode<K, V> = node;
|
|
1163
1344
|
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1345
|
+
while (current !== this.root && current.color === 'BLACK') {
|
|
1346
|
+
const parent: RedBlackTreeNode<K, V> | undefined = current.parent;
|
|
1347
|
+
if (!parent) break;
|
|
1167
1348
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1349
|
+
const nodeIsLeft = current === parent.left;
|
|
1350
|
+
let sibling = nodeIsLeft ? parent.right : parent.left;
|
|
1170
1351
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1352
|
+
// Case 1: sibling is RED → rotate to get a BLACK sibling
|
|
1353
|
+
if (sibling && sibling.color === 'RED') {
|
|
1354
|
+
sibling.color = 'BLACK';
|
|
1355
|
+
parent.color = 'RED';
|
|
1356
|
+
if (nodeIsLeft) {
|
|
1174
1357
|
this._leftRotate(parent);
|
|
1175
1358
|
sibling = parent.right;
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
if ((sibling?.left?.color ?? 'BLACK') === 'BLACK') {
|
|
1179
|
-
if (sibling) sibling.color = 'RED';
|
|
1180
|
-
node = parent;
|
|
1181
1359
|
} else {
|
|
1182
|
-
if (sibling?.left) sibling.left.color = 'BLACK';
|
|
1183
|
-
if (sibling) sibling.color = parent.color;
|
|
1184
|
-
parent.color = 'BLACK';
|
|
1185
1360
|
this._rightRotate(parent);
|
|
1186
|
-
|
|
1361
|
+
sibling = parent.left;
|
|
1187
1362
|
}
|
|
1188
|
-
}
|
|
1189
|
-
let sibling = parent.left;
|
|
1363
|
+
}
|
|
1190
1364
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
if (parent) sibling = parent.left;
|
|
1196
|
-
}
|
|
1365
|
+
const sibLeft = sibling?.left;
|
|
1366
|
+
const sibRight = sibling?.right;
|
|
1367
|
+
const sibLeftBlack = !sibLeft || sibLeft === NIL || sibLeft.color === 'BLACK';
|
|
1368
|
+
const sibRightBlack = !sibRight || sibRight === NIL || sibRight.color === 'BLACK';
|
|
1197
1369
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1370
|
+
if (sibLeftBlack && sibRightBlack) {
|
|
1371
|
+
// Case 2: sibling's children are both BLACK → recolor sibling RED, move up
|
|
1372
|
+
if (sibling) sibling.color = 'RED';
|
|
1373
|
+
current = parent;
|
|
1374
|
+
} else {
|
|
1375
|
+
if (nodeIsLeft) {
|
|
1376
|
+
// Case 3: sibling's right child is BLACK → rotate sibling right first
|
|
1377
|
+
if (sibRightBlack) {
|
|
1378
|
+
if (sibLeft) sibLeft.color = 'BLACK';
|
|
1379
|
+
if (sibling) sibling.color = 'RED';
|
|
1380
|
+
if (sibling) this._rightRotate(sibling);
|
|
1381
|
+
sibling = parent.right;
|
|
1382
|
+
}
|
|
1383
|
+
// Case 4: sibling's right child is RED → final rotation
|
|
1203
1384
|
if (sibling) sibling.color = parent.color;
|
|
1204
|
-
|
|
1385
|
+
parent.color = 'BLACK';
|
|
1386
|
+
if (sibling?.right) sibling.right.color = 'BLACK';
|
|
1205
1387
|
this._leftRotate(parent);
|
|
1206
|
-
|
|
1388
|
+
} else {
|
|
1389
|
+
// Case 3 (mirror): sibling's left child is BLACK → rotate sibling left first
|
|
1390
|
+
if (sibLeftBlack) {
|
|
1391
|
+
if (sibRight) sibRight.color = 'BLACK';
|
|
1392
|
+
if (sibling) sibling.color = 'RED';
|
|
1393
|
+
if (sibling) this._leftRotate(sibling);
|
|
1394
|
+
sibling = parent.left;
|
|
1395
|
+
}
|
|
1396
|
+
// Case 4 (mirror): sibling's left child is RED → final rotation
|
|
1397
|
+
if (sibling) sibling.color = parent.color;
|
|
1398
|
+
parent.color = 'BLACK';
|
|
1399
|
+
if (sibling?.left) sibling.left.color = 'BLACK';
|
|
1400
|
+
this._rightRotate(parent);
|
|
1207
1401
|
}
|
|
1402
|
+
current = this.root!;
|
|
1208
1403
|
}
|
|
1209
1404
|
}
|
|
1210
1405
|
|
|
1211
|
-
|
|
1212
|
-
node.color = 'BLACK';
|
|
1213
|
-
}
|
|
1406
|
+
current.color = 'BLACK';
|
|
1214
1407
|
}
|
|
1215
1408
|
|
|
1216
1409
|
/**
|