linked-list-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 +14 -50
- package/dist/cjs/index.cjs +1537 -267
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +1543 -264
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +1537 -268
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +1543 -265
- 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/linked-list-typed.js +1540 -262
- package/dist/umd/linked-list-typed.js.map +1 -1
- package/dist/umd/linked-list-typed.min.js +1 -1
- package/dist/umd/linked-list-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
package/dist/cjs/index.cjs
CHANGED
|
@@ -725,11 +725,37 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
725
725
|
return list;
|
|
726
726
|
}
|
|
727
727
|
/**
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
728
|
+
* Append an element/node to the tail.
|
|
729
|
+
* @remarks Time O(1), Space O(1)
|
|
730
|
+
* @param elementOrNode - Element or node to append.
|
|
731
|
+
* @returns True when appended.
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
* @example
|
|
744
|
+
* // basic SinglyLinkedList creation and push operation
|
|
745
|
+
* // Create a simple SinglyLinkedList with initial values
|
|
746
|
+
* const list = new SinglyLinkedList([1, 2, 3, 4, 5]);
|
|
747
|
+
*
|
|
748
|
+
* // Verify the list maintains insertion order
|
|
749
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
750
|
+
*
|
|
751
|
+
* // Check length
|
|
752
|
+
* console.log(list.length); // 5;
|
|
753
|
+
*
|
|
754
|
+
* // Push a new element to the end
|
|
755
|
+
* list.push(6);
|
|
756
|
+
* console.log(list.length); // 6;
|
|
757
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
758
|
+
*/
|
|
733
759
|
push(elementOrNode) {
|
|
734
760
|
const newNode = this._ensureNode(elementOrNode);
|
|
735
761
|
if (!this.head) {
|
|
@@ -743,10 +769,36 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
743
769
|
return true;
|
|
744
770
|
}
|
|
745
771
|
/**
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
772
|
+
* Remove and return the tail element.
|
|
773
|
+
* @remarks Time O(N), Space O(1)
|
|
774
|
+
* @returns Removed element or undefined.
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
* @example
|
|
787
|
+
* // SinglyLinkedList pop and shift operations
|
|
788
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
789
|
+
*
|
|
790
|
+
* // Pop removes from the end
|
|
791
|
+
* const last = list.pop();
|
|
792
|
+
* console.log(last); // 50;
|
|
793
|
+
*
|
|
794
|
+
* // Shift removes from the beginning
|
|
795
|
+
* const first = list.shift();
|
|
796
|
+
* console.log(first); // 10;
|
|
797
|
+
*
|
|
798
|
+
* // Verify remaining elements
|
|
799
|
+
* console.log([...list]); // [20, 30, 40];
|
|
800
|
+
* console.log(list.length); // 3;
|
|
801
|
+
*/
|
|
750
802
|
pop() {
|
|
751
803
|
if (!this.head) return void 0;
|
|
752
804
|
if (this.head === this.tail) {
|
|
@@ -765,10 +817,26 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
765
817
|
return value;
|
|
766
818
|
}
|
|
767
819
|
/**
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
820
|
+
* Remove and return the head element.
|
|
821
|
+
* @remarks Time O(1), Space O(1)
|
|
822
|
+
* @returns Removed element or undefined.
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
* @example
|
|
835
|
+
* // Remove from the front
|
|
836
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30]);
|
|
837
|
+
* console.log(list.shift()); // 10;
|
|
838
|
+
* console.log(list.length); // 2;
|
|
839
|
+
*/
|
|
772
840
|
shift() {
|
|
773
841
|
if (!this.head) return void 0;
|
|
774
842
|
const removed = this.head;
|
|
@@ -778,11 +846,42 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
778
846
|
return removed.value;
|
|
779
847
|
}
|
|
780
848
|
/**
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
849
|
+
* Prepend an element/node to the head.
|
|
850
|
+
* @remarks Time O(1), Space O(1)
|
|
851
|
+
* @param elementOrNode - Element or node to prepend.
|
|
852
|
+
* @returns True when prepended.
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
* @example
|
|
865
|
+
* // SinglyLinkedList unshift and forward traversal
|
|
866
|
+
* const list = new SinglyLinkedList<number>([20, 30, 40]);
|
|
867
|
+
*
|
|
868
|
+
* // Unshift adds to the beginning
|
|
869
|
+
* list.unshift(10);
|
|
870
|
+
* console.log([...list]); // [10, 20, 30, 40];
|
|
871
|
+
*
|
|
872
|
+
* // Access elements (forward traversal only for singly linked)
|
|
873
|
+
* const second = list.at(1);
|
|
874
|
+
* console.log(second); // 20;
|
|
875
|
+
*
|
|
876
|
+
* // SinglyLinkedList allows forward iteration only
|
|
877
|
+
* const elements: number[] = [];
|
|
878
|
+
* for (const item of list) {
|
|
879
|
+
* elements.push(item);
|
|
880
|
+
* }
|
|
881
|
+
* console.log(elements); // [10, 20, 30, 40];
|
|
882
|
+
*
|
|
883
|
+
* console.log(list.length); // 4;
|
|
884
|
+
*/
|
|
786
885
|
unshift(elementOrNode) {
|
|
787
886
|
const newNode = this._ensureNode(elementOrNode);
|
|
788
887
|
if (!this.head) {
|
|
@@ -838,11 +937,28 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
838
937
|
return void 0;
|
|
839
938
|
}
|
|
840
939
|
/**
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
940
|
+
* Get the element at a given index.
|
|
941
|
+
* @remarks Time O(N), Space O(1)
|
|
942
|
+
* @param index - Zero-based index.
|
|
943
|
+
* @returns Element or undefined.
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
* @example
|
|
956
|
+
* // Access element by index
|
|
957
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c', 'd']);
|
|
958
|
+
* console.log(list.at(0)); // 'a';
|
|
959
|
+
* console.log(list.at(2)); // 'c';
|
|
960
|
+
* console.log(list.at(3)); // 'd';
|
|
961
|
+
*/
|
|
846
962
|
at(index) {
|
|
847
963
|
if (index < 0 || index >= this._length) return void 0;
|
|
848
964
|
let current = this.head;
|
|
@@ -859,11 +975,23 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
859
975
|
return elementNodeOrPredicate instanceof SinglyLinkedListNode;
|
|
860
976
|
}
|
|
861
977
|
/**
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
978
|
+
* Get the node reference at a given index.
|
|
979
|
+
* @remarks Time O(N), Space O(1)
|
|
980
|
+
* @param index - Zero-based index.
|
|
981
|
+
* @returns Node or undefined.
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
* @example
|
|
991
|
+
* // Get node at index
|
|
992
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
993
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
994
|
+
*/
|
|
867
995
|
getNodeAt(index) {
|
|
868
996
|
if (index < 0 || index >= this._length) return void 0;
|
|
869
997
|
let current = this.head;
|
|
@@ -871,11 +999,24 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
871
999
|
return current;
|
|
872
1000
|
}
|
|
873
1001
|
/**
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1002
|
+
* Delete the element at an index.
|
|
1003
|
+
* @remarks Time O(N), Space O(1)
|
|
1004
|
+
* @param index - Zero-based index.
|
|
1005
|
+
* @returns Removed element or undefined.
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
* @example
|
|
1015
|
+
* // Remove by index
|
|
1016
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
1017
|
+
* list.deleteAt(1);
|
|
1018
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
1019
|
+
*/
|
|
879
1020
|
deleteAt(index) {
|
|
880
1021
|
if (index < 0 || index >= this._length) return void 0;
|
|
881
1022
|
if (index === 0) return this.shift();
|
|
@@ -888,11 +1029,24 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
888
1029
|
return value;
|
|
889
1030
|
}
|
|
890
1031
|
/**
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1032
|
+
* Delete the first match by value/node.
|
|
1033
|
+
* @remarks Time O(N), Space O(1)
|
|
1034
|
+
* @param [elementOrNode] - Element or node to remove; if omitted/undefined, nothing happens.
|
|
1035
|
+
* @returns True if removed.
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
* @example
|
|
1045
|
+
* // Remove first occurrence
|
|
1046
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 2]);
|
|
1047
|
+
* list.delete(2);
|
|
1048
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
1049
|
+
*/
|
|
896
1050
|
delete(elementOrNode) {
|
|
897
1051
|
if (elementOrNode === void 0 || !this.head) return false;
|
|
898
1052
|
const node = this.isNode(elementOrNode) ? elementOrNode : this.getNode(elementOrNode);
|
|
@@ -909,12 +1063,25 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
909
1063
|
return true;
|
|
910
1064
|
}
|
|
911
1065
|
/**
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1066
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
1067
|
+
* @remarks Time O(N), Space O(1)
|
|
1068
|
+
* @param index - Zero-based index.
|
|
1069
|
+
* @param newElementOrNode - Element or node to insert.
|
|
1070
|
+
* @returns True if inserted.
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
* @example
|
|
1080
|
+
* // Insert at index
|
|
1081
|
+
* const list = new SinglyLinkedList<number>([1, 3]);
|
|
1082
|
+
* list.addAt(1, 2);
|
|
1083
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
1084
|
+
*/
|
|
918
1085
|
addAt(index, newElementOrNode) {
|
|
919
1086
|
if (index < 0 || index > this._length) return false;
|
|
920
1087
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -940,28 +1107,70 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
940
1107
|
return true;
|
|
941
1108
|
}
|
|
942
1109
|
/**
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1110
|
+
* Check whether the list is empty.
|
|
1111
|
+
* @remarks Time O(1), Space O(1)
|
|
1112
|
+
* @returns True if length is 0.
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
* @example
|
|
1123
|
+
* // Check empty
|
|
1124
|
+
* console.log(new SinglyLinkedList().isEmpty()); // true;
|
|
1125
|
+
*/
|
|
947
1126
|
isEmpty() {
|
|
948
1127
|
return this._length === 0;
|
|
949
1128
|
}
|
|
950
1129
|
/**
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1130
|
+
* Remove all nodes and reset length.
|
|
1131
|
+
* @remarks Time O(N), Space O(1)
|
|
1132
|
+
* @returns void
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
* @example
|
|
1143
|
+
* // Remove all
|
|
1144
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1145
|
+
* list.clear();
|
|
1146
|
+
* console.log(list.isEmpty()); // true;
|
|
1147
|
+
*/
|
|
955
1148
|
clear() {
|
|
956
1149
|
this._head = void 0;
|
|
957
1150
|
this._tail = void 0;
|
|
958
1151
|
this._length = 0;
|
|
959
1152
|
}
|
|
960
1153
|
/**
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1154
|
+
* Reverse the list in place.
|
|
1155
|
+
* @remarks Time O(N), Space O(1)
|
|
1156
|
+
* @returns This list.
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
* @example
|
|
1169
|
+
* // Reverse the list in-place
|
|
1170
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4]);
|
|
1171
|
+
* list.reverse();
|
|
1172
|
+
* console.log([...list]); // [4, 3, 2, 1];
|
|
1173
|
+
*/
|
|
965
1174
|
reverse() {
|
|
966
1175
|
if (!this.head || this.head === this.tail) return this;
|
|
967
1176
|
let prev;
|
|
@@ -1136,22 +1345,64 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1136
1345
|
return false;
|
|
1137
1346
|
}
|
|
1138
1347
|
/**
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1348
|
+
* Deep clone this list (values are copied by reference).
|
|
1349
|
+
* @remarks Time O(N), Space O(N)
|
|
1350
|
+
* @returns A new list with the same element sequence.
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
* @example
|
|
1361
|
+
* // Deep copy
|
|
1362
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1363
|
+
* const copy = list.clone();
|
|
1364
|
+
* copy.pop();
|
|
1365
|
+
* console.log(list.length); // 3;
|
|
1366
|
+
* console.log(copy.length); // 2;
|
|
1367
|
+
*/
|
|
1143
1368
|
clone() {
|
|
1144
1369
|
const out = this._createInstance();
|
|
1145
1370
|
for (const v of this) out.push(v);
|
|
1146
1371
|
return out;
|
|
1147
1372
|
}
|
|
1148
1373
|
/**
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1374
|
+
* Filter values into a new list of the same class.
|
|
1375
|
+
* @remarks Time O(N), Space O(N)
|
|
1376
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
1377
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1378
|
+
* @returns A new list with kept values.
|
|
1379
|
+
|
|
1380
|
+
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
* @example
|
|
1391
|
+
* // SinglyLinkedList filter and map operations
|
|
1392
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
1393
|
+
*
|
|
1394
|
+
* // Filter even numbers
|
|
1395
|
+
* const filtered = list.filter(value => value % 2 === 0);
|
|
1396
|
+
* console.log(filtered.length); // 2;
|
|
1397
|
+
*
|
|
1398
|
+
* // Map to double values
|
|
1399
|
+
* const doubled = list.map(value => value * 2);
|
|
1400
|
+
* console.log(doubled.length); // 5;
|
|
1401
|
+
*
|
|
1402
|
+
* // Use reduce to sum
|
|
1403
|
+
* const sum = list.reduce((acc, value) => acc + value, 0);
|
|
1404
|
+
* console.log(sum); // 15;
|
|
1405
|
+
*/
|
|
1155
1406
|
filter(callback, thisArg) {
|
|
1156
1407
|
const out = this._createInstance();
|
|
1157
1408
|
let index = 0;
|
|
@@ -1175,15 +1426,31 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1175
1426
|
return out;
|
|
1176
1427
|
}
|
|
1177
1428
|
/**
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1429
|
+
* Map values into a new list (possibly different element type).
|
|
1430
|
+
* @remarks Time O(N), Space O(N)
|
|
1431
|
+
* @template EM
|
|
1432
|
+
* @template RM
|
|
1433
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
1434
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
1435
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1436
|
+
* @returns A new SinglyLinkedList with mapped values.
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
* @example
|
|
1449
|
+
* // Transform elements
|
|
1450
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1451
|
+
* const doubled = list.map(n => n * 2);
|
|
1452
|
+
* console.log([...doubled]); // [2, 4, 6];
|
|
1453
|
+
*/
|
|
1187
1454
|
map(callback, options, thisArg) {
|
|
1188
1455
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1189
1456
|
let index = 0;
|
|
@@ -1459,11 +1726,37 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1459
1726
|
return elementNodeOrPredicate instanceof DoublyLinkedListNode;
|
|
1460
1727
|
}
|
|
1461
1728
|
/**
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1729
|
+
* Append an element/node to the tail.
|
|
1730
|
+
* @remarks Time O(1), Space O(1)
|
|
1731
|
+
* @param elementOrNode - Element or node to append.
|
|
1732
|
+
* @returns True when appended.
|
|
1733
|
+
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
|
|
1738
|
+
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
|
|
1744
|
+
* @example
|
|
1745
|
+
* // basic DoublyLinkedList creation and push operation
|
|
1746
|
+
* // Create a simple DoublyLinkedList with initial values
|
|
1747
|
+
* const list = new DoublyLinkedList([1, 2, 3, 4, 5]);
|
|
1748
|
+
*
|
|
1749
|
+
* // Verify the list maintains insertion order
|
|
1750
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
1751
|
+
*
|
|
1752
|
+
* // Check length
|
|
1753
|
+
* console.log(list.length); // 5;
|
|
1754
|
+
*
|
|
1755
|
+
* // Push a new element to the end
|
|
1756
|
+
* list.push(6);
|
|
1757
|
+
* console.log(list.length); // 6;
|
|
1758
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
1759
|
+
*/
|
|
1467
1760
|
push(elementOrNode) {
|
|
1468
1761
|
const newNode = this._ensureNode(elementOrNode);
|
|
1469
1762
|
if (!this.head) {
|
|
@@ -1479,10 +1772,36 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1479
1772
|
return true;
|
|
1480
1773
|
}
|
|
1481
1774
|
/**
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1775
|
+
* Remove and return the tail element.
|
|
1776
|
+
* @remarks Time O(1), Space O(1)
|
|
1777
|
+
* @returns Removed element or undefined.
|
|
1778
|
+
|
|
1779
|
+
|
|
1780
|
+
|
|
1781
|
+
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
|
|
1785
|
+
|
|
1786
|
+
|
|
1787
|
+
|
|
1788
|
+
|
|
1789
|
+
* @example
|
|
1790
|
+
* // DoublyLinkedList pop and shift operations
|
|
1791
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
1792
|
+
*
|
|
1793
|
+
* // Pop removes from the end
|
|
1794
|
+
* const last = list.pop();
|
|
1795
|
+
* console.log(last); // 50;
|
|
1796
|
+
*
|
|
1797
|
+
* // Shift removes from the beginning
|
|
1798
|
+
* const first = list.shift();
|
|
1799
|
+
* console.log(first); // 10;
|
|
1800
|
+
*
|
|
1801
|
+
* // Verify remaining elements
|
|
1802
|
+
* console.log([...list]); // [20, 30, 40];
|
|
1803
|
+
* console.log(list.length); // 3;
|
|
1804
|
+
*/
|
|
1486
1805
|
pop() {
|
|
1487
1806
|
if (!this.tail) return void 0;
|
|
1488
1807
|
const removed = this.tail;
|
|
@@ -1497,10 +1816,26 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1497
1816
|
return removed.value;
|
|
1498
1817
|
}
|
|
1499
1818
|
/**
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1819
|
+
* Remove and return the head element.
|
|
1820
|
+
* @remarks Time O(1), Space O(1)
|
|
1821
|
+
* @returns Removed element or undefined.
|
|
1822
|
+
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
|
|
1829
|
+
|
|
1830
|
+
|
|
1831
|
+
|
|
1832
|
+
|
|
1833
|
+
* @example
|
|
1834
|
+
* // Remove from the front
|
|
1835
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
1836
|
+
* console.log(list.shift()); // 10;
|
|
1837
|
+
* console.log(list.first); // 20;
|
|
1838
|
+
*/
|
|
1504
1839
|
shift() {
|
|
1505
1840
|
if (!this.head) return void 0;
|
|
1506
1841
|
const removed = this.head;
|
|
@@ -1515,11 +1850,27 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1515
1850
|
return removed.value;
|
|
1516
1851
|
}
|
|
1517
1852
|
/**
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1853
|
+
* Prepend an element/node to the head.
|
|
1854
|
+
* @remarks Time O(1), Space O(1)
|
|
1855
|
+
* @param elementOrNode - Element or node to prepend.
|
|
1856
|
+
* @returns True when prepended.
|
|
1857
|
+
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
|
|
1861
|
+
|
|
1862
|
+
|
|
1863
|
+
|
|
1864
|
+
|
|
1865
|
+
|
|
1866
|
+
|
|
1867
|
+
|
|
1868
|
+
* @example
|
|
1869
|
+
* // Add to the front
|
|
1870
|
+
* const list = new DoublyLinkedList<number>([2, 3]);
|
|
1871
|
+
* list.unshift(1);
|
|
1872
|
+
* console.log([...list]); // [1, 2, 3];
|
|
1873
|
+
*/
|
|
1523
1874
|
unshift(elementOrNode) {
|
|
1524
1875
|
const newNode = this._ensureNode(elementOrNode);
|
|
1525
1876
|
if (!this.head) {
|
|
@@ -1563,11 +1914,27 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1563
1914
|
return ans;
|
|
1564
1915
|
}
|
|
1565
1916
|
/**
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1917
|
+
* Get the element at a given index.
|
|
1918
|
+
* @remarks Time O(N), Space O(1)
|
|
1919
|
+
* @param index - Zero-based index.
|
|
1920
|
+
* @returns Element or undefined.
|
|
1921
|
+
|
|
1922
|
+
|
|
1923
|
+
|
|
1924
|
+
|
|
1925
|
+
|
|
1926
|
+
|
|
1927
|
+
|
|
1928
|
+
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
|
|
1932
|
+
* @example
|
|
1933
|
+
* // Access by index
|
|
1934
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
1935
|
+
* console.log(list.at(1)); // 'b';
|
|
1936
|
+
* console.log(list.at(2)); // 'c';
|
|
1937
|
+
*/
|
|
1571
1938
|
at(index) {
|
|
1572
1939
|
if (index < 0 || index >= this._length) return void 0;
|
|
1573
1940
|
let current = this.head;
|
|
@@ -1575,11 +1942,23 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1575
1942
|
return current?.value;
|
|
1576
1943
|
}
|
|
1577
1944
|
/**
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1945
|
+
* Get the node reference at a given index.
|
|
1946
|
+
* @remarks Time O(N), Space O(1)
|
|
1947
|
+
* @param index - Zero-based index.
|
|
1948
|
+
* @returns Node or undefined.
|
|
1949
|
+
|
|
1950
|
+
|
|
1951
|
+
|
|
1952
|
+
|
|
1953
|
+
|
|
1954
|
+
|
|
1955
|
+
|
|
1956
|
+
|
|
1957
|
+
* @example
|
|
1958
|
+
* // Get node at index
|
|
1959
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
1960
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
1961
|
+
*/
|
|
1583
1962
|
getNodeAt(index) {
|
|
1584
1963
|
if (index < 0 || index >= this._length) return void 0;
|
|
1585
1964
|
let current = this.head;
|
|
@@ -1618,12 +1997,25 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1618
1997
|
return void 0;
|
|
1619
1998
|
}
|
|
1620
1999
|
/**
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
2000
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
2001
|
+
* @remarks Time O(N), Space O(1)
|
|
2002
|
+
* @param index - Zero-based index.
|
|
2003
|
+
* @param newElementOrNode - Element or node to insert.
|
|
2004
|
+
* @returns True if inserted.
|
|
2005
|
+
|
|
2006
|
+
|
|
2007
|
+
|
|
2008
|
+
|
|
2009
|
+
|
|
2010
|
+
|
|
2011
|
+
|
|
2012
|
+
|
|
2013
|
+
* @example
|
|
2014
|
+
* // Insert at position
|
|
2015
|
+
* const list = new DoublyLinkedList<number>([1, 3]);
|
|
2016
|
+
* list.addAt(1, 2);
|
|
2017
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
2018
|
+
*/
|
|
1627
2019
|
addAt(index, newElementOrNode) {
|
|
1628
2020
|
if (index < 0 || index > this._length) return false;
|
|
1629
2021
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -1690,11 +2082,24 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1690
2082
|
return true;
|
|
1691
2083
|
}
|
|
1692
2084
|
/**
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
2085
|
+
* Delete the element at an index.
|
|
2086
|
+
* @remarks Time O(N), Space O(1)
|
|
2087
|
+
* @param index - Zero-based index.
|
|
2088
|
+
* @returns Removed element or undefined.
|
|
2089
|
+
|
|
2090
|
+
|
|
2091
|
+
|
|
2092
|
+
|
|
2093
|
+
|
|
2094
|
+
|
|
2095
|
+
|
|
2096
|
+
|
|
2097
|
+
* @example
|
|
2098
|
+
* // Remove by index
|
|
2099
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2100
|
+
* list.deleteAt(1);
|
|
2101
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
2102
|
+
*/
|
|
1698
2103
|
deleteAt(index) {
|
|
1699
2104
|
if (index < 0 || index >= this._length) return;
|
|
1700
2105
|
if (index === 0) return this.shift();
|
|
@@ -1708,11 +2113,24 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1708
2113
|
return removedNode.value;
|
|
1709
2114
|
}
|
|
1710
2115
|
/**
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
2116
|
+
* Delete the first match by value/node.
|
|
2117
|
+
* @remarks Time O(N), Space O(1)
|
|
2118
|
+
* @param [elementOrNode] - Element or node to remove.
|
|
2119
|
+
* @returns True if removed.
|
|
2120
|
+
|
|
2121
|
+
|
|
2122
|
+
|
|
2123
|
+
|
|
2124
|
+
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
|
|
2128
|
+
* @example
|
|
2129
|
+
* // Remove first occurrence
|
|
2130
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 2]);
|
|
2131
|
+
* list.delete(2);
|
|
2132
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
2133
|
+
*/
|
|
1716
2134
|
delete(elementOrNode) {
|
|
1717
2135
|
const node = this.getNode(elementOrNode);
|
|
1718
2136
|
if (!node) return false;
|
|
@@ -1728,29 +2146,68 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1728
2146
|
return true;
|
|
1729
2147
|
}
|
|
1730
2148
|
/**
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2149
|
+
* Check whether the list is empty.
|
|
2150
|
+
* @remarks Time O(1), Space O(1)
|
|
2151
|
+
* @returns True if length is 0.
|
|
2152
|
+
|
|
2153
|
+
|
|
2154
|
+
|
|
2155
|
+
|
|
2156
|
+
|
|
2157
|
+
|
|
2158
|
+
|
|
2159
|
+
|
|
2160
|
+
|
|
2161
|
+
* @example
|
|
2162
|
+
* // Check empty
|
|
2163
|
+
* console.log(new DoublyLinkedList().isEmpty()); // true;
|
|
2164
|
+
*/
|
|
1735
2165
|
isEmpty() {
|
|
1736
2166
|
return this._length === 0;
|
|
1737
2167
|
}
|
|
1738
2168
|
/**
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
2169
|
+
* Remove all nodes and reset length.
|
|
2170
|
+
* @remarks Time O(N), Space O(1)
|
|
2171
|
+
* @returns void
|
|
2172
|
+
|
|
2173
|
+
|
|
2174
|
+
|
|
2175
|
+
|
|
2176
|
+
|
|
2177
|
+
|
|
2178
|
+
|
|
2179
|
+
|
|
2180
|
+
|
|
2181
|
+
* @example
|
|
2182
|
+
* // Remove all
|
|
2183
|
+
* const list = new DoublyLinkedList<number>([1, 2]);
|
|
2184
|
+
* list.clear();
|
|
2185
|
+
* console.log(list.isEmpty()); // true;
|
|
2186
|
+
*/
|
|
1743
2187
|
clear() {
|
|
1744
2188
|
this._head = void 0;
|
|
1745
2189
|
this._tail = void 0;
|
|
1746
2190
|
this._length = 0;
|
|
1747
2191
|
}
|
|
1748
2192
|
/**
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
2193
|
+
* Find the first value matching a predicate scanning forward.
|
|
2194
|
+
* @remarks Time O(N), Space O(1)
|
|
2195
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2196
|
+
* @returns Matched value or undefined.
|
|
2197
|
+
|
|
2198
|
+
|
|
2199
|
+
|
|
2200
|
+
|
|
2201
|
+
|
|
2202
|
+
|
|
2203
|
+
|
|
2204
|
+
|
|
2205
|
+
* @example
|
|
2206
|
+
* // Search with predicate
|
|
2207
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
2208
|
+
* const found = list.search(node => node.value > 15);
|
|
2209
|
+
* console.log(found); // 20;
|
|
2210
|
+
*/
|
|
1754
2211
|
search(elementNodeOrPredicate) {
|
|
1755
2212
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1756
2213
|
let current = this.head;
|
|
@@ -1761,11 +2218,25 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1761
2218
|
return void 0;
|
|
1762
2219
|
}
|
|
1763
2220
|
/**
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
2221
|
+
* Find the first value matching a predicate scanning backward.
|
|
2222
|
+
* @remarks Time O(N), Space O(1)
|
|
2223
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2224
|
+
* @returns Matched value or undefined.
|
|
2225
|
+
|
|
2226
|
+
|
|
2227
|
+
|
|
2228
|
+
|
|
2229
|
+
|
|
2230
|
+
|
|
2231
|
+
|
|
2232
|
+
|
|
2233
|
+
* @example
|
|
2234
|
+
* // Find value scanning from tail
|
|
2235
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4]);
|
|
2236
|
+
* // getBackward scans from tail to head, returns first match
|
|
2237
|
+
* const found = list.getBackward(node => node.value < 4);
|
|
2238
|
+
* console.log(found); // 3;
|
|
2239
|
+
*/
|
|
1769
2240
|
getBackward(elementNodeOrPredicate) {
|
|
1770
2241
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1771
2242
|
let current = this.tail;
|
|
@@ -1776,10 +2247,26 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1776
2247
|
return void 0;
|
|
1777
2248
|
}
|
|
1778
2249
|
/**
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
2250
|
+
* Reverse the list in place.
|
|
2251
|
+
* @remarks Time O(N), Space O(1)
|
|
2252
|
+
* @returns This list.
|
|
2253
|
+
|
|
2254
|
+
|
|
2255
|
+
|
|
2256
|
+
|
|
2257
|
+
|
|
2258
|
+
|
|
2259
|
+
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
|
|
2263
|
+
|
|
2264
|
+
* @example
|
|
2265
|
+
* // Reverse in-place
|
|
2266
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2267
|
+
* list.reverse();
|
|
2268
|
+
* console.log([...list]); // [3, 2, 1];
|
|
2269
|
+
*/
|
|
1783
2270
|
reverse() {
|
|
1784
2271
|
let current = this.head;
|
|
1785
2272
|
[this._head, this._tail] = [this.tail, this.head];
|
|
@@ -1801,22 +2288,53 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1801
2288
|
return this;
|
|
1802
2289
|
}
|
|
1803
2290
|
/**
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
2291
|
+
* Deep clone this list (values are copied by reference).
|
|
2292
|
+
* @remarks Time O(N), Space O(N)
|
|
2293
|
+
* @returns A new list with the same element sequence.
|
|
2294
|
+
|
|
2295
|
+
|
|
2296
|
+
|
|
2297
|
+
|
|
2298
|
+
|
|
2299
|
+
|
|
2300
|
+
|
|
2301
|
+
|
|
2302
|
+
|
|
2303
|
+
* @example
|
|
2304
|
+
* // Deep copy
|
|
2305
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2306
|
+
* const copy = list.clone();
|
|
2307
|
+
* copy.pop();
|
|
2308
|
+
* console.log(list.length); // 3;
|
|
2309
|
+
*/
|
|
1808
2310
|
clone() {
|
|
1809
2311
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1810
2312
|
for (const v of this) out.push(v);
|
|
1811
2313
|
return out;
|
|
1812
2314
|
}
|
|
1813
2315
|
/**
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
2316
|
+
* Filter values into a new list of the same class.
|
|
2317
|
+
* @remarks Time O(N), Space O(N)
|
|
2318
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
2319
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
2320
|
+
* @returns A new list with kept values.
|
|
2321
|
+
|
|
2322
|
+
|
|
2323
|
+
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
* @example
|
|
2333
|
+
* // Filter elements
|
|
2334
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
2335
|
+
* const evens = list.filter(n => n % 2 === 0);
|
|
2336
|
+
* console.log([...evens]); // [2, 4];
|
|
2337
|
+
*/
|
|
1820
2338
|
filter(callback, thisArg) {
|
|
1821
2339
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1822
2340
|
let index = 0;
|
|
@@ -1840,15 +2358,40 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1840
2358
|
return out;
|
|
1841
2359
|
}
|
|
1842
2360
|
/**
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
2361
|
+
* Map values into a new list (possibly different element type).
|
|
2362
|
+
* @remarks Time O(N), Space O(N)
|
|
2363
|
+
* @template EM
|
|
2364
|
+
* @template RM
|
|
2365
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
2366
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
2367
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
2368
|
+
* @returns A new DoublyLinkedList with mapped values.
|
|
2369
|
+
|
|
2370
|
+
|
|
2371
|
+
|
|
2372
|
+
|
|
2373
|
+
|
|
2374
|
+
|
|
2375
|
+
|
|
2376
|
+
|
|
2377
|
+
|
|
2378
|
+
|
|
2379
|
+
|
|
2380
|
+
* @example
|
|
2381
|
+
* // DoublyLinkedList for...of iteration and map operation
|
|
2382
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
2383
|
+
*
|
|
2384
|
+
* // Iterate through list
|
|
2385
|
+
* const doubled = list.map(value => value * 2);
|
|
2386
|
+
* console.log(doubled.length); // 5;
|
|
2387
|
+
*
|
|
2388
|
+
* // Use for...of loop
|
|
2389
|
+
* const result: number[] = [];
|
|
2390
|
+
* for (const item of list) {
|
|
2391
|
+
* result.push(item);
|
|
2392
|
+
* }
|
|
2393
|
+
* console.log(result); // [1, 2, 3, 4, 5];
|
|
2394
|
+
*/
|
|
1852
2395
|
map(callback, options, thisArg) {
|
|
1853
2396
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1854
2397
|
let index = 0;
|
|
@@ -1937,6 +2480,237 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1937
2480
|
}
|
|
1938
2481
|
};
|
|
1939
2482
|
|
|
2483
|
+
// src/common/error.ts
|
|
2484
|
+
var ERR = {
|
|
2485
|
+
// Range / index
|
|
2486
|
+
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
|
|
2487
|
+
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
|
|
2488
|
+
// Type / argument
|
|
2489
|
+
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
|
|
2490
|
+
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
|
|
2491
|
+
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
|
|
2492
|
+
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
|
|
2493
|
+
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
|
|
2494
|
+
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
|
|
2495
|
+
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
|
|
2496
|
+
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
|
|
2497
|
+
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
|
|
2498
|
+
// State / operation
|
|
2499
|
+
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
|
|
2500
|
+
// Matrix
|
|
2501
|
+
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
|
|
2502
|
+
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
|
|
2503
|
+
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
|
|
2504
|
+
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
|
|
2505
|
+
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
|
|
2506
|
+
};
|
|
2507
|
+
|
|
2508
|
+
// src/common/index.ts
|
|
2509
|
+
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
2510
|
+
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
2511
|
+
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
2512
|
+
return DFSOperation2;
|
|
2513
|
+
})(DFSOperation || {});
|
|
2514
|
+
var Range = class {
|
|
2515
|
+
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
2516
|
+
this.low = low;
|
|
2517
|
+
this.high = high;
|
|
2518
|
+
this.includeLow = includeLow;
|
|
2519
|
+
this.includeHigh = includeHigh;
|
|
2520
|
+
}
|
|
2521
|
+
static {
|
|
2522
|
+
__name(this, "Range");
|
|
2523
|
+
}
|
|
2524
|
+
// Determine whether a key is within the range
|
|
2525
|
+
isInRange(key, comparator) {
|
|
2526
|
+
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
2527
|
+
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
2528
|
+
return lowCheck && highCheck;
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
|
|
2532
|
+
// src/data-structures/base/iterable-entry-base.ts
|
|
2533
|
+
var IterableEntryBase = class {
|
|
2534
|
+
static {
|
|
2535
|
+
__name(this, "IterableEntryBase");
|
|
2536
|
+
}
|
|
2537
|
+
/**
|
|
2538
|
+
* Default iterator yielding `[key, value]` entries.
|
|
2539
|
+
* @returns Iterator of `[K, V]`.
|
|
2540
|
+
* @remarks Time O(n) to iterate, Space O(1)
|
|
2541
|
+
*/
|
|
2542
|
+
*[Symbol.iterator](...args) {
|
|
2543
|
+
yield* this._getIterator(...args);
|
|
2544
|
+
}
|
|
2545
|
+
/**
|
|
2546
|
+
* Iterate over `[key, value]` pairs (may yield `undefined` values).
|
|
2547
|
+
* @returns Iterator of `[K, V | undefined]`.
|
|
2548
|
+
* @remarks Time O(n), Space O(1)
|
|
2549
|
+
*/
|
|
2550
|
+
*entries() {
|
|
2551
|
+
for (const item of this) {
|
|
2552
|
+
yield item;
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Iterate over keys only.
|
|
2557
|
+
* @returns Iterator of keys.
|
|
2558
|
+
* @remarks Time O(n), Space O(1)
|
|
2559
|
+
*/
|
|
2560
|
+
*keys() {
|
|
2561
|
+
for (const item of this) {
|
|
2562
|
+
yield item[0];
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
/**
|
|
2566
|
+
* Iterate over values only.
|
|
2567
|
+
* @returns Iterator of values.
|
|
2568
|
+
* @remarks Time O(n), Space O(1)
|
|
2569
|
+
*/
|
|
2570
|
+
*values() {
|
|
2571
|
+
for (const item of this) {
|
|
2572
|
+
yield item[1];
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
/**
|
|
2576
|
+
* Test whether all entries satisfy the predicate.
|
|
2577
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
2578
|
+
* @param thisArg - Optional `this` for callback.
|
|
2579
|
+
* @returns `true` if all pass; otherwise `false`.
|
|
2580
|
+
* @remarks Time O(n), Space O(1)
|
|
2581
|
+
*/
|
|
2582
|
+
every(predicate, thisArg) {
|
|
2583
|
+
let index = 0;
|
|
2584
|
+
for (const item of this) {
|
|
2585
|
+
if (!predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
2586
|
+
return false;
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
return true;
|
|
2590
|
+
}
|
|
2591
|
+
/**
|
|
2592
|
+
* Test whether any entry satisfies the predicate.
|
|
2593
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
2594
|
+
* @param thisArg - Optional `this` for callback.
|
|
2595
|
+
* @returns `true` if any passes; otherwise `false`.
|
|
2596
|
+
* @remarks Time O(n), Space O(1)
|
|
2597
|
+
*/
|
|
2598
|
+
some(predicate, thisArg) {
|
|
2599
|
+
let index = 0;
|
|
2600
|
+
for (const item of this) {
|
|
2601
|
+
if (predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
2602
|
+
return true;
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
return false;
|
|
2606
|
+
}
|
|
2607
|
+
/**
|
|
2608
|
+
* Visit each entry, left-to-right.
|
|
2609
|
+
* @param callbackfn - `(key, value, index, self) => void`.
|
|
2610
|
+
* @param thisArg - Optional `this` for callback.
|
|
2611
|
+
* @remarks Time O(n), Space O(1)
|
|
2612
|
+
*/
|
|
2613
|
+
forEach(callbackfn, thisArg) {
|
|
2614
|
+
let index = 0;
|
|
2615
|
+
for (const item of this) {
|
|
2616
|
+
const [key, value] = item;
|
|
2617
|
+
callbackfn.call(thisArg, value, key, index++, this);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
/**
|
|
2621
|
+
* Find the first entry that matches a predicate.
|
|
2622
|
+
* @param callbackfn - `(key, value, index, self) => boolean`.
|
|
2623
|
+
* @param thisArg - Optional `this` for callback.
|
|
2624
|
+
* @returns Matching `[key, value]` or `undefined`.
|
|
2625
|
+
* @remarks Time O(n), Space O(1)
|
|
2626
|
+
*/
|
|
2627
|
+
find(callbackfn, thisArg) {
|
|
2628
|
+
let index = 0;
|
|
2629
|
+
for (const item of this) {
|
|
2630
|
+
const [key, value] = item;
|
|
2631
|
+
if (callbackfn.call(thisArg, value, key, index++, this)) return item;
|
|
2632
|
+
}
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
/**
|
|
2636
|
+
* Whether the given key exists.
|
|
2637
|
+
* @param key - Key to test.
|
|
2638
|
+
* @returns `true` if found; otherwise `false`.
|
|
2639
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
2640
|
+
*/
|
|
2641
|
+
has(key) {
|
|
2642
|
+
for (const item of this) {
|
|
2643
|
+
const [itemKey] = item;
|
|
2644
|
+
if (itemKey === key) return true;
|
|
2645
|
+
}
|
|
2646
|
+
return false;
|
|
2647
|
+
}
|
|
2648
|
+
/**
|
|
2649
|
+
* Whether there exists an entry with the given value.
|
|
2650
|
+
* @param value - Value to test.
|
|
2651
|
+
* @returns `true` if found; otherwise `false`.
|
|
2652
|
+
* @remarks Time O(n), Space O(1)
|
|
2653
|
+
*/
|
|
2654
|
+
hasValue(value) {
|
|
2655
|
+
for (const [, elementValue] of this) {
|
|
2656
|
+
if (elementValue === value) return true;
|
|
2657
|
+
}
|
|
2658
|
+
return false;
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Get the value under a key.
|
|
2662
|
+
* @param key - Key to look up.
|
|
2663
|
+
* @returns Value or `undefined`.
|
|
2664
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
2665
|
+
*/
|
|
2666
|
+
get(key) {
|
|
2667
|
+
for (const item of this) {
|
|
2668
|
+
const [itemKey, value] = item;
|
|
2669
|
+
if (itemKey === key) return value;
|
|
2670
|
+
}
|
|
2671
|
+
return;
|
|
2672
|
+
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Reduce entries into a single accumulator.
|
|
2675
|
+
* @param callbackfn - `(acc, value, key, index, self) => acc`.
|
|
2676
|
+
* @param initialValue - Initial accumulator.
|
|
2677
|
+
* @returns Final accumulator.
|
|
2678
|
+
* @remarks Time O(n), Space O(1)
|
|
2679
|
+
*/
|
|
2680
|
+
reduce(callbackfn, initialValue) {
|
|
2681
|
+
let accumulator = initialValue;
|
|
2682
|
+
let index = 0;
|
|
2683
|
+
for (const item of this) {
|
|
2684
|
+
const [key, value] = item;
|
|
2685
|
+
accumulator = callbackfn(accumulator, value, key, index++, this);
|
|
2686
|
+
}
|
|
2687
|
+
return accumulator;
|
|
2688
|
+
}
|
|
2689
|
+
/**
|
|
2690
|
+
* Converts data structure to `[key, value]` pairs.
|
|
2691
|
+
* @returns Array of entries.
|
|
2692
|
+
* @remarks Time O(n), Space O(n)
|
|
2693
|
+
*/
|
|
2694
|
+
toArray() {
|
|
2695
|
+
return [...this];
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* Visualize the iterable as an array of `[key, value]` pairs (or a custom string).
|
|
2699
|
+
* @returns Array of entries (default) or a string.
|
|
2700
|
+
* @remarks Time O(n), Space O(n)
|
|
2701
|
+
*/
|
|
2702
|
+
toVisual() {
|
|
2703
|
+
return [...this];
|
|
2704
|
+
}
|
|
2705
|
+
/**
|
|
2706
|
+
* Print a human-friendly representation to the console.
|
|
2707
|
+
* @remarks Time O(n), Space O(n)
|
|
2708
|
+
*/
|
|
2709
|
+
print() {
|
|
2710
|
+
console.log(this.toVisual());
|
|
2711
|
+
}
|
|
2712
|
+
};
|
|
2713
|
+
|
|
1940
2714
|
// src/data-structures/linked-list/skip-linked-list.ts
|
|
1941
2715
|
var SkipListNode = class {
|
|
1942
2716
|
static {
|
|
@@ -1948,165 +2722,660 @@ var SkipListNode = class {
|
|
|
1948
2722
|
constructor(key, value, level) {
|
|
1949
2723
|
this.key = key;
|
|
1950
2724
|
this.value = value;
|
|
1951
|
-
this.forward = new Array(level);
|
|
2725
|
+
this.forward = new Array(level).fill(void 0);
|
|
1952
2726
|
}
|
|
1953
2727
|
};
|
|
1954
|
-
var SkipList = class {
|
|
2728
|
+
var SkipList = class _SkipList extends IterableEntryBase {
|
|
1955
2729
|
static {
|
|
1956
2730
|
__name(this, "SkipList");
|
|
1957
2731
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
if (
|
|
1965
|
-
|
|
2732
|
+
#comparator;
|
|
2733
|
+
#isDefaultComparator;
|
|
2734
|
+
constructor(entries = [], options = {}) {
|
|
2735
|
+
super();
|
|
2736
|
+
const { comparator, toEntryFn, maxLevel, probability } = options;
|
|
2737
|
+
if (typeof maxLevel === "number" && maxLevel > 0) this._maxLevel = maxLevel;
|
|
2738
|
+
if (typeof probability === "number" && probability > 0 && probability < 1) this._probability = probability;
|
|
2739
|
+
this.#isDefaultComparator = comparator === void 0;
|
|
2740
|
+
this.#comparator = comparator ?? _SkipList.createDefaultComparator();
|
|
2741
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
2742
|
+
for (const item of entries) {
|
|
2743
|
+
let k;
|
|
2744
|
+
let v;
|
|
2745
|
+
if (toEntryFn) {
|
|
2746
|
+
[k, v] = toEntryFn(item);
|
|
2747
|
+
} else {
|
|
2748
|
+
if (!Array.isArray(item) || item.length < 2) {
|
|
2749
|
+
throw new TypeError(ERR.invalidEntry("SkipList"));
|
|
2750
|
+
}
|
|
2751
|
+
[k, v] = item;
|
|
2752
|
+
}
|
|
2753
|
+
this.set(k, v);
|
|
1966
2754
|
}
|
|
1967
2755
|
}
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2756
|
+
/**
|
|
2757
|
+
* Creates a default comparator supporting number, string, Date, and bigint.
|
|
2758
|
+
*/
|
|
2759
|
+
static createDefaultComparator() {
|
|
2760
|
+
return (a, b) => {
|
|
2761
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
2762
|
+
if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("SkipList"));
|
|
2763
|
+
return a - b;
|
|
2764
|
+
}
|
|
2765
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
2766
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
2767
|
+
}
|
|
2768
|
+
if (a instanceof Date && b instanceof Date) {
|
|
2769
|
+
const ta = a.getTime(), tb = b.getTime();
|
|
2770
|
+
if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("SkipList"));
|
|
2771
|
+
return ta - tb;
|
|
2772
|
+
}
|
|
2773
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
2774
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
2775
|
+
}
|
|
2776
|
+
throw new TypeError(ERR.comparatorRequired("SkipList"));
|
|
2777
|
+
};
|
|
1971
2778
|
}
|
|
2779
|
+
// ─── Internal state ──────────────────────────────────────────
|
|
2780
|
+
_head;
|
|
1972
2781
|
_level = 0;
|
|
1973
|
-
|
|
1974
|
-
return this._level;
|
|
1975
|
-
}
|
|
2782
|
+
_size = 0;
|
|
1976
2783
|
_maxLevel = 16;
|
|
2784
|
+
_probability = 0.5;
|
|
2785
|
+
// ─── Size & lifecycle ────────────────────────────────────────
|
|
2786
|
+
get size() {
|
|
2787
|
+
return this._size;
|
|
2788
|
+
}
|
|
1977
2789
|
get maxLevel() {
|
|
1978
2790
|
return this._maxLevel;
|
|
1979
2791
|
}
|
|
1980
|
-
_probability = 0.5;
|
|
1981
2792
|
get probability() {
|
|
1982
2793
|
return this._probability;
|
|
1983
2794
|
}
|
|
1984
|
-
get
|
|
1985
|
-
|
|
1986
|
-
|
|
2795
|
+
get comparator() {
|
|
2796
|
+
return this.#comparator;
|
|
2797
|
+
}
|
|
2798
|
+
/**
|
|
2799
|
+
* Check if empty
|
|
2800
|
+
|
|
2801
|
+
|
|
2802
|
+
|
|
2803
|
+
|
|
2804
|
+
|
|
2805
|
+
|
|
2806
|
+
|
|
2807
|
+
|
|
2808
|
+
* @example
|
|
2809
|
+
* // Check if empty
|
|
2810
|
+
* const sl = new SkipList<number, string>();
|
|
2811
|
+
* console.log(sl.isEmpty()); // true;
|
|
2812
|
+
*/
|
|
2813
|
+
isEmpty() {
|
|
2814
|
+
return this._size === 0;
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* Remove all entries
|
|
2818
|
+
|
|
2819
|
+
|
|
2820
|
+
|
|
2821
|
+
|
|
2822
|
+
|
|
2823
|
+
|
|
2824
|
+
|
|
2825
|
+
|
|
2826
|
+
* @example
|
|
2827
|
+
* // Remove all entries
|
|
2828
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
2829
|
+
* sl.clear();
|
|
2830
|
+
* console.log(sl.isEmpty()); // true;
|
|
2831
|
+
*/
|
|
2832
|
+
clear() {
|
|
2833
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
2834
|
+
this._level = 0;
|
|
2835
|
+
this._size = 0;
|
|
2836
|
+
}
|
|
2837
|
+
/**
|
|
2838
|
+
* Create independent copy
|
|
2839
|
+
|
|
2840
|
+
|
|
2841
|
+
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
|
|
2845
|
+
|
|
2846
|
+
|
|
2847
|
+
* @example
|
|
2848
|
+
* // Create independent copy
|
|
2849
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
2850
|
+
* const copy = sl.clone();
|
|
2851
|
+
* copy.delete(1);
|
|
2852
|
+
* console.log(sl.has(1)); // true;
|
|
2853
|
+
*/
|
|
2854
|
+
clone() {
|
|
2855
|
+
return new _SkipList(this, {
|
|
2856
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
2857
|
+
maxLevel: this._maxLevel,
|
|
2858
|
+
probability: this._probability
|
|
2859
|
+
});
|
|
2860
|
+
}
|
|
2861
|
+
// ─── Core CRUD ───────────────────────────────────────────────
|
|
2862
|
+
/**
|
|
2863
|
+
* Insert or update a key-value pair. Returns `this` for chaining.
|
|
2864
|
+
* Unique keys only — if key exists, value is updated in place.
|
|
2865
|
+
|
|
2866
|
+
|
|
2867
|
+
|
|
2868
|
+
|
|
2869
|
+
|
|
2870
|
+
|
|
2871
|
+
|
|
2872
|
+
|
|
2873
|
+
|
|
2874
|
+
|
|
2875
|
+
|
|
2876
|
+
* @example
|
|
2877
|
+
* // In-memory sorted key-value store
|
|
2878
|
+
* const store = new SkipList<number, string>();
|
|
2879
|
+
*
|
|
2880
|
+
* store.set(3, 'three');
|
|
2881
|
+
* store.set(1, 'one');
|
|
2882
|
+
* store.set(5, 'five');
|
|
2883
|
+
* store.set(2, 'two');
|
|
2884
|
+
*
|
|
2885
|
+
* console.log(store.get(3)); // 'three';
|
|
2886
|
+
* console.log(store.get(1)); // 'one';
|
|
2887
|
+
* console.log(store.get(5)); // 'five';
|
|
2888
|
+
*
|
|
2889
|
+
* // Update existing key
|
|
2890
|
+
* store.set(3, 'THREE');
|
|
2891
|
+
* console.log(store.get(3)); // 'THREE';
|
|
2892
|
+
*/
|
|
2893
|
+
set(key, value) {
|
|
2894
|
+
const cmp = this.#comparator;
|
|
2895
|
+
const update = this._findUpdate(key);
|
|
2896
|
+
const existing = update[0].forward[0];
|
|
2897
|
+
if (existing && cmp(existing.key, key) === 0) {
|
|
2898
|
+
existing.value = value;
|
|
2899
|
+
return this;
|
|
2900
|
+
}
|
|
2901
|
+
const newLevel = this._randomLevel();
|
|
2902
|
+
const newNode = new SkipListNode(key, value, newLevel);
|
|
2903
|
+
if (newLevel > this._level) {
|
|
2904
|
+
for (let i = this._level; i < newLevel; i++) {
|
|
2905
|
+
update[i] = this._head;
|
|
2906
|
+
}
|
|
2907
|
+
this._level = newLevel;
|
|
2908
|
+
}
|
|
2909
|
+
for (let i = 0; i < newLevel; i++) {
|
|
2910
|
+
newNode.forward[i] = update[i].forward[i];
|
|
2911
|
+
update[i].forward[i] = newNode;
|
|
2912
|
+
}
|
|
2913
|
+
this._size++;
|
|
2914
|
+
return this;
|
|
1987
2915
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2916
|
+
/**
|
|
2917
|
+
* Get the value for a key, or `undefined` if not found.
|
|
2918
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
2919
|
+
|
|
2920
|
+
|
|
2921
|
+
|
|
2922
|
+
|
|
2923
|
+
|
|
2924
|
+
|
|
2925
|
+
|
|
2926
|
+
|
|
2927
|
+
|
|
2928
|
+
|
|
2929
|
+
|
|
2930
|
+
* @example
|
|
2931
|
+
* // Building a sorted index
|
|
2932
|
+
* type Product = { id: number; name: string; price: number };
|
|
2933
|
+
* const products: Product[] = [
|
|
2934
|
+
* { id: 1, name: 'Widget', price: 25 },
|
|
2935
|
+
* { id: 2, name: 'Gadget', price: 50 },
|
|
2936
|
+
* { id: 3, name: 'Doohickey', price: 15 }
|
|
2937
|
+
* ];
|
|
2938
|
+
*
|
|
2939
|
+
* const index = new SkipList<number, Product>(products as any, {
|
|
2940
|
+
* toEntryFn: (p: any) => [p.price, p]
|
|
2941
|
+
* });
|
|
2942
|
+
*
|
|
2943
|
+
* // Iterate in sorted order by price
|
|
2944
|
+
* const names = [...index.values()].map(p => p!.name);
|
|
2945
|
+
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
2946
|
+
*
|
|
2947
|
+
* // Range search: products between $20 and $60
|
|
2948
|
+
* const range = index.rangeSearch([20, 60]);
|
|
2949
|
+
* console.log(range.map(([, p]) => p!.name)); // ['Widget', 'Gadget'];
|
|
2950
|
+
*/
|
|
2951
|
+
get(key) {
|
|
2952
|
+
const node = this._findNode(key);
|
|
2953
|
+
return node ? node.value : void 0;
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Check if a key exists.
|
|
2957
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
2958
|
+
|
|
2959
|
+
|
|
2960
|
+
|
|
2961
|
+
|
|
2962
|
+
|
|
2963
|
+
|
|
2964
|
+
|
|
2965
|
+
|
|
2966
|
+
|
|
2967
|
+
|
|
2968
|
+
|
|
2969
|
+
* @example
|
|
2970
|
+
* // Check key existence
|
|
2971
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [3, 'c'], [5, 'e']]);
|
|
2972
|
+
* console.log(sl.has(3)); // true;
|
|
2973
|
+
* console.log(sl.has(4)); // false;
|
|
2974
|
+
*/
|
|
2975
|
+
has(key) {
|
|
2976
|
+
return this._findNode(key) !== void 0;
|
|
2977
|
+
}
|
|
2978
|
+
/**
|
|
2979
|
+
* Delete a key. Returns `true` if the key was found and removed.
|
|
2980
|
+
|
|
2981
|
+
|
|
2982
|
+
|
|
2983
|
+
|
|
2984
|
+
|
|
2985
|
+
|
|
2986
|
+
|
|
2987
|
+
|
|
2988
|
+
|
|
2989
|
+
|
|
2990
|
+
|
|
2991
|
+
* @example
|
|
2992
|
+
* // Fast lookup with deletion
|
|
2993
|
+
* const cache = new SkipList<string, number>();
|
|
2994
|
+
*
|
|
2995
|
+
* cache.set('alpha', 1);
|
|
2996
|
+
* cache.set('beta', 2);
|
|
2997
|
+
* cache.set('gamma', 3);
|
|
2998
|
+
*
|
|
2999
|
+
* console.log(cache.has('beta')); // true;
|
|
3000
|
+
* cache.delete('beta');
|
|
3001
|
+
* console.log(cache.has('beta')); // false;
|
|
3002
|
+
* console.log(cache.size); // 2;
|
|
3003
|
+
*/
|
|
3004
|
+
delete(key) {
|
|
3005
|
+
const cmp = this.#comparator;
|
|
3006
|
+
const update = this._findUpdate(key);
|
|
3007
|
+
const target = update[0].forward[0];
|
|
3008
|
+
if (!target || cmp(target.key, key) !== 0) return false;
|
|
3009
|
+
for (let i = 0; i < this._level; i++) {
|
|
3010
|
+
if (update[i].forward[i] !== target) break;
|
|
3011
|
+
update[i].forward[i] = target.forward[i];
|
|
3012
|
+
}
|
|
3013
|
+
while (this._level > 0 && !this._head.forward[this._level - 1]) {
|
|
3014
|
+
this._level--;
|
|
3015
|
+
}
|
|
3016
|
+
this._size--;
|
|
3017
|
+
return true;
|
|
3018
|
+
}
|
|
3019
|
+
// ─── Navigation ──────────────────────────────────────────────
|
|
3020
|
+
/**
|
|
3021
|
+
* Returns the first (smallest key) entry, or `undefined` if empty.
|
|
3022
|
+
|
|
3023
|
+
|
|
3024
|
+
|
|
3025
|
+
|
|
3026
|
+
|
|
3027
|
+
|
|
3028
|
+
|
|
3029
|
+
|
|
3030
|
+
|
|
3031
|
+
|
|
3032
|
+
|
|
3033
|
+
* @example
|
|
3034
|
+
* // Access the minimum entry
|
|
3035
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3036
|
+
* console.log(sl.first()); // [1, 'a'];
|
|
3037
|
+
*/
|
|
3038
|
+
first() {
|
|
3039
|
+
const node = this._head.forward[0];
|
|
3040
|
+
return node ? [node.key, node.value] : void 0;
|
|
3041
|
+
}
|
|
3042
|
+
/**
|
|
3043
|
+
* Returns the last (largest key) entry, or `undefined` if empty.
|
|
3044
|
+
|
|
3045
|
+
|
|
3046
|
+
|
|
3047
|
+
|
|
3048
|
+
|
|
3049
|
+
|
|
3050
|
+
|
|
3051
|
+
|
|
3052
|
+
|
|
3053
|
+
|
|
3054
|
+
|
|
3055
|
+
* @example
|
|
3056
|
+
* // Access the maximum entry
|
|
3057
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3058
|
+
* console.log(sl.last()); // [5, 'e'];
|
|
3059
|
+
*/
|
|
3060
|
+
last() {
|
|
3061
|
+
let current = this._head;
|
|
3062
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
1991
3063
|
while (current.forward[i]) {
|
|
1992
3064
|
current = current.forward[i];
|
|
1993
3065
|
}
|
|
1994
3066
|
}
|
|
1995
|
-
return current.value;
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
3067
|
+
return current === this._head ? void 0 : [current.key, current.value];
|
|
3068
|
+
}
|
|
3069
|
+
/**
|
|
3070
|
+
* Remove and return the first (smallest key) entry.
|
|
3071
|
+
|
|
3072
|
+
|
|
3073
|
+
|
|
3074
|
+
|
|
3075
|
+
|
|
3076
|
+
|
|
3077
|
+
|
|
3078
|
+
|
|
3079
|
+
* @example
|
|
3080
|
+
* // Remove and return smallest
|
|
3081
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
3082
|
+
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
3083
|
+
* console.log(sl.size); // 2;
|
|
3084
|
+
*/
|
|
3085
|
+
pollFirst() {
|
|
3086
|
+
const entry = this.first();
|
|
3087
|
+
if (!entry) return void 0;
|
|
3088
|
+
this.delete(entry[0]);
|
|
3089
|
+
return entry;
|
|
3090
|
+
}
|
|
3091
|
+
/**
|
|
3092
|
+
* Remove and return the last (largest key) entry.
|
|
3093
|
+
|
|
3094
|
+
|
|
3095
|
+
|
|
3096
|
+
|
|
3097
|
+
|
|
3098
|
+
|
|
3099
|
+
|
|
3100
|
+
|
|
3101
|
+
* @example
|
|
3102
|
+
* // Remove and return largest
|
|
3103
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
3104
|
+
* console.log(sl.pollLast()); // [3, 'c'];
|
|
3105
|
+
* console.log(sl.size); // 2;
|
|
3106
|
+
*/
|
|
3107
|
+
pollLast() {
|
|
3108
|
+
const entry = this.last();
|
|
3109
|
+
if (!entry) return void 0;
|
|
3110
|
+
this.delete(entry[0]);
|
|
3111
|
+
return entry;
|
|
3112
|
+
}
|
|
3113
|
+
/**
|
|
3114
|
+
* Least entry ≥ key, or `undefined`.
|
|
3115
|
+
|
|
3116
|
+
|
|
3117
|
+
|
|
3118
|
+
|
|
3119
|
+
|
|
3120
|
+
|
|
3121
|
+
|
|
3122
|
+
|
|
3123
|
+
|
|
3124
|
+
|
|
3125
|
+
|
|
3126
|
+
* @example
|
|
3127
|
+
* // Least entry ≥ key
|
|
3128
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
3129
|
+
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
3130
|
+
* console.log(sl.ceiling(20)); // [20, 'b'];
|
|
3131
|
+
*/
|
|
3132
|
+
ceiling(key) {
|
|
3133
|
+
const cmp = this.#comparator;
|
|
3134
|
+
let current = this._head;
|
|
3135
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3136
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
2003
3137
|
current = current.forward[i];
|
|
2004
3138
|
}
|
|
2005
|
-
update[i] = current;
|
|
2006
|
-
}
|
|
2007
|
-
for (let i = 0; i < newNode.forward.length; i++) {
|
|
2008
|
-
newNode.forward[i] = update[i].forward[i];
|
|
2009
|
-
update[i].forward[i] = newNode;
|
|
2010
3139
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
3140
|
+
const node = current.forward[0];
|
|
3141
|
+
return node ? [node.key, node.value] : void 0;
|
|
3142
|
+
}
|
|
3143
|
+
/**
|
|
3144
|
+
* Greatest entry ≤ key, or `undefined`.
|
|
3145
|
+
|
|
3146
|
+
|
|
3147
|
+
|
|
3148
|
+
|
|
3149
|
+
|
|
3150
|
+
|
|
3151
|
+
|
|
3152
|
+
|
|
3153
|
+
|
|
3154
|
+
|
|
3155
|
+
|
|
3156
|
+
* @example
|
|
3157
|
+
* // Greatest entry ≤ key
|
|
3158
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
3159
|
+
* console.log(sl.floor(25)); // [20, 'b'];
|
|
3160
|
+
* console.log(sl.floor(5)); // undefined;
|
|
3161
|
+
*/
|
|
3162
|
+
floor(key) {
|
|
3163
|
+
const cmp = this.#comparator;
|
|
3164
|
+
let current = this._head;
|
|
3165
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3166
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
3167
|
+
current = current.forward[i];
|
|
3168
|
+
}
|
|
2013
3169
|
}
|
|
3170
|
+
const result = current === this._head ? void 0 : current;
|
|
3171
|
+
if (result && cmp(result.key, key) <= 0) return [result.key, result.value];
|
|
3172
|
+
return void 0;
|
|
2014
3173
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
3174
|
+
/**
|
|
3175
|
+
* Least entry strictly > key, or `undefined`.
|
|
3176
|
+
|
|
3177
|
+
|
|
3178
|
+
|
|
3179
|
+
|
|
3180
|
+
|
|
3181
|
+
|
|
3182
|
+
|
|
3183
|
+
|
|
3184
|
+
* @example
|
|
3185
|
+
* // Strictly greater entry
|
|
3186
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
3187
|
+
* console.log(sl.higher(15)); // [20, 'b'];
|
|
3188
|
+
* console.log(sl.higher(30)); // undefined;
|
|
3189
|
+
*/
|
|
3190
|
+
higher(key) {
|
|
3191
|
+
const cmp = this.#comparator;
|
|
3192
|
+
let current = this._head;
|
|
3193
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3194
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
2019
3195
|
current = current.forward[i];
|
|
2020
3196
|
}
|
|
2021
3197
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
3198
|
+
const node = current.forward[0];
|
|
3199
|
+
return node ? [node.key, node.value] : void 0;
|
|
3200
|
+
}
|
|
3201
|
+
/**
|
|
3202
|
+
* Greatest entry strictly < key, or `undefined`.
|
|
3203
|
+
|
|
3204
|
+
|
|
3205
|
+
|
|
3206
|
+
|
|
3207
|
+
|
|
3208
|
+
|
|
3209
|
+
|
|
3210
|
+
|
|
3211
|
+
* @example
|
|
3212
|
+
* // Strictly less entry
|
|
3213
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
3214
|
+
* console.log(sl.lower(25)); // [20, 'b'];
|
|
3215
|
+
* console.log(sl.lower(10)); // undefined;
|
|
3216
|
+
*/
|
|
3217
|
+
lower(key) {
|
|
3218
|
+
const cmp = this.#comparator;
|
|
3219
|
+
let current = this._head;
|
|
3220
|
+
let result;
|
|
3221
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3222
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
3223
|
+
current = current.forward[i];
|
|
3224
|
+
}
|
|
3225
|
+
if (current !== this._head && cmp(current.key, key) < 0) {
|
|
3226
|
+
result = current;
|
|
3227
|
+
}
|
|
2025
3228
|
}
|
|
2026
|
-
return void 0;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
3229
|
+
return result ? [result.key, result.value] : void 0;
|
|
3230
|
+
}
|
|
3231
|
+
/**
|
|
3232
|
+
* Returns entries within the given key range.
|
|
3233
|
+
|
|
3234
|
+
|
|
3235
|
+
|
|
3236
|
+
|
|
3237
|
+
|
|
3238
|
+
|
|
3239
|
+
|
|
3240
|
+
|
|
3241
|
+
|
|
3242
|
+
|
|
3243
|
+
|
|
3244
|
+
* @example
|
|
3245
|
+
* // Find entries in a range
|
|
3246
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]);
|
|
3247
|
+
* const result = sl.rangeSearch([2, 4]);
|
|
3248
|
+
* console.log(result); // [[2, 'b'], [3, 'c'], [4, 'd']];
|
|
3249
|
+
*/
|
|
3250
|
+
rangeSearch(range, options = {}) {
|
|
3251
|
+
const { lowInclusive = true, highInclusive = true } = options;
|
|
3252
|
+
const [low, high] = range;
|
|
3253
|
+
const cmp = this.#comparator;
|
|
3254
|
+
const out = [];
|
|
3255
|
+
let current = this._head;
|
|
3256
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3257
|
+
while (current.forward[i] && cmp(current.forward[i].key, low) < 0) {
|
|
2036
3258
|
current = current.forward[i];
|
|
2037
3259
|
}
|
|
2038
|
-
update[i] = current;
|
|
2039
3260
|
}
|
|
2040
3261
|
current = current.forward[0];
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
while (this.level > 0 && !this.head.forward[this.level - 1]) {
|
|
2049
|
-
this._level--;
|
|
3262
|
+
while (current) {
|
|
3263
|
+
const cmpHigh = cmp(current.key, high);
|
|
3264
|
+
if (cmpHigh > 0) break;
|
|
3265
|
+
if (cmpHigh === 0 && !highInclusive) break;
|
|
3266
|
+
const cmpLow = cmp(current.key, low);
|
|
3267
|
+
if (cmpLow > 0 || cmpLow === 0 && lowInclusive) {
|
|
3268
|
+
out.push([current.key, current.value]);
|
|
2050
3269
|
}
|
|
2051
|
-
|
|
3270
|
+
current = current.forward[0];
|
|
2052
3271
|
}
|
|
2053
|
-
return
|
|
3272
|
+
return out;
|
|
2054
3273
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
3274
|
+
// ─── Functional (overrides) ──────────────────────────────────
|
|
3275
|
+
/**
|
|
3276
|
+
* Creates a new SkipList with entries transformed by callback.
|
|
3277
|
+
|
|
3278
|
+
|
|
3279
|
+
|
|
3280
|
+
|
|
3281
|
+
|
|
3282
|
+
|
|
3283
|
+
|
|
3284
|
+
|
|
3285
|
+
* @example
|
|
3286
|
+
* // Transform entries
|
|
3287
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
3288
|
+
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
3289
|
+
* console.log([...mapped.values()]); // ['A', 'B'];
|
|
3290
|
+
*/
|
|
3291
|
+
map(callback, options) {
|
|
3292
|
+
const out = new _SkipList([], options ?? {});
|
|
3293
|
+
let i = 0;
|
|
3294
|
+
for (const [k, v] of this) {
|
|
3295
|
+
const [nk, nv] = callback(v, k, i++, this);
|
|
3296
|
+
out.set(nk, nv);
|
|
3297
|
+
}
|
|
3298
|
+
return out;
|
|
3299
|
+
}
|
|
3300
|
+
/**
|
|
3301
|
+
* Creates a new SkipList with entries that pass the predicate.
|
|
3302
|
+
|
|
3303
|
+
|
|
3304
|
+
|
|
3305
|
+
|
|
3306
|
+
|
|
3307
|
+
|
|
3308
|
+
|
|
3309
|
+
|
|
3310
|
+
* @example
|
|
3311
|
+
* // Filter entries
|
|
3312
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
3313
|
+
* const result = sl.filter((v, k) => k > 1);
|
|
3314
|
+
* console.log(result.size); // 2;
|
|
3315
|
+
*/
|
|
3316
|
+
filter(callbackfn, thisArg) {
|
|
3317
|
+
const out = new _SkipList([], {
|
|
3318
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
3319
|
+
maxLevel: this._maxLevel,
|
|
3320
|
+
probability: this._probability
|
|
3321
|
+
});
|
|
3322
|
+
let i = 0;
|
|
3323
|
+
for (const [k, v] of this) {
|
|
3324
|
+
const ok = callbackfn.call(thisArg, v, k, i++, this);
|
|
3325
|
+
if (ok) out.set(k, v);
|
|
3326
|
+
}
|
|
3327
|
+
return out;
|
|
3328
|
+
}
|
|
3329
|
+
// ─── Iterator (required by IterableEntryBase) ────────────────
|
|
3330
|
+
_getIterator() {
|
|
3331
|
+
const head = this._head;
|
|
3332
|
+
return (function* () {
|
|
3333
|
+
let node = head.forward[0];
|
|
3334
|
+
while (node) {
|
|
3335
|
+
yield [node.key, node.value];
|
|
3336
|
+
node = node.forward[0];
|
|
3337
|
+
}
|
|
3338
|
+
})();
|
|
3339
|
+
}
|
|
3340
|
+
// ─── Internal helpers ────────────────────────────────────────
|
|
3341
|
+
/**
|
|
3342
|
+
* Finds the update array (predecessors at each level) for a given key.
|
|
3343
|
+
*/
|
|
3344
|
+
_findUpdate(key) {
|
|
3345
|
+
const cmp = this.#comparator;
|
|
3346
|
+
const update = new Array(this._maxLevel).fill(this._head);
|
|
3347
|
+
let current = this._head;
|
|
3348
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3349
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
2059
3350
|
current = current.forward[i];
|
|
2060
3351
|
}
|
|
3352
|
+
update[i] = current;
|
|
2061
3353
|
}
|
|
2062
|
-
|
|
2063
|
-
return nextNode ? nextNode.value : void 0;
|
|
3354
|
+
return update;
|
|
2064
3355
|
}
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
3356
|
+
/**
|
|
3357
|
+
* Finds the node for a given key, or undefined.
|
|
3358
|
+
*/
|
|
3359
|
+
_findNode(key) {
|
|
3360
|
+
const cmp = this.#comparator;
|
|
3361
|
+
let current = this._head;
|
|
3362
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3363
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
2070
3364
|
current = current.forward[i];
|
|
2071
3365
|
}
|
|
2072
|
-
if (current.key < key) {
|
|
2073
|
-
lastLess = current;
|
|
2074
|
-
}
|
|
2075
3366
|
}
|
|
2076
|
-
|
|
3367
|
+
const candidate = current.forward[0];
|
|
3368
|
+
if (candidate && cmp(candidate.key, key) === 0) return candidate;
|
|
3369
|
+
return void 0;
|
|
2077
3370
|
}
|
|
2078
3371
|
_randomLevel() {
|
|
2079
3372
|
let level = 1;
|
|
2080
|
-
while (Math.random() < this.
|
|
3373
|
+
while (Math.random() < this._probability && level < this._maxLevel) {
|
|
2081
3374
|
level++;
|
|
2082
3375
|
}
|
|
2083
3376
|
return level;
|
|
2084
3377
|
}
|
|
2085
3378
|
};
|
|
2086
|
-
|
|
2087
|
-
// src/common/index.ts
|
|
2088
|
-
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
2089
|
-
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
2090
|
-
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
2091
|
-
return DFSOperation2;
|
|
2092
|
-
})(DFSOperation || {});
|
|
2093
|
-
var Range = class {
|
|
2094
|
-
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
2095
|
-
this.low = low;
|
|
2096
|
-
this.high = high;
|
|
2097
|
-
this.includeLow = includeLow;
|
|
2098
|
-
this.includeHigh = includeHigh;
|
|
2099
|
-
}
|
|
2100
|
-
static {
|
|
2101
|
-
__name(this, "Range");
|
|
2102
|
-
}
|
|
2103
|
-
// Determine whether a key is within the range
|
|
2104
|
-
isInRange(key, comparator) {
|
|
2105
|
-
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
2106
|
-
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
2107
|
-
return lowCheck && highCheck;
|
|
2108
|
-
}
|
|
2109
|
-
};
|
|
2110
3379
|
/**
|
|
2111
3380
|
* data-structure-typed
|
|
2112
3381
|
*
|
|
@@ -2118,6 +3387,7 @@ var Range = class {
|
|
|
2118
3387
|
exports.DFSOperation = DFSOperation;
|
|
2119
3388
|
exports.DoublyLinkedList = DoublyLinkedList;
|
|
2120
3389
|
exports.DoublyLinkedListNode = DoublyLinkedListNode;
|
|
3390
|
+
exports.ERR = ERR;
|
|
2121
3391
|
exports.Range = Range;
|
|
2122
3392
|
exports.SinglyLinkedList = SinglyLinkedList;
|
|
2123
3393
|
exports.SinglyLinkedListNode = SinglyLinkedListNode;
|