linked-list-typed 2.4.5 → 2.5.1
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 +2586 -292
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs-legacy/index.cjs +2592 -289
- package/dist/cjs-legacy/index.cjs.map +1 -1
- package/dist/esm/index.mjs +2586 -292
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm-legacy/index.mjs +2592 -289
- package/dist/esm-legacy/index.mjs.map +1 -1
- package/dist/types/data-structures/base/index.d.ts +1 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
- package/dist/types/data-structures/base/iterable-entry-base.d.ts +8 -8
- package/dist/types/data-structures/base/linear-base.d.ts +3 -3
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +380 -51
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +487 -147
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +956 -80
- package/dist/types/data-structures/binary-tree/bst.d.ts +816 -29
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +610 -31
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +326 -135
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +3781 -6
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +3607 -201
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +2874 -65
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +3528 -6
- package/dist/types/data-structures/graph/abstract-graph.d.ts +4 -4
- package/dist/types/data-structures/graph/directed-graph.d.ts +429 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +393 -59
- package/dist/types/data-structures/hash/hash-map.d.ts +473 -89
- package/dist/types/data-structures/heap/heap.d.ts +581 -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 +646 -47
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +596 -68
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +793 -12
- package/dist/types/data-structures/matrix/matrix.d.ts +499 -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 +593 -71
- package/dist/types/data-structures/queue/queue.d.ts +463 -42
- package/dist/types/data-structures/stack/stack.d.ts +384 -32
- package/dist/types/data-structures/trie/trie.d.ts +470 -48
- package/dist/types/interfaces/graph.d.ts +1 -1
- package/dist/types/types/common.d.ts +2 -2
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
- package/dist/types/types/data-structures/heap/heap.d.ts +1 -0
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
- package/dist/types/types/data-structures/priority-queue/priority-queue.d.ts +1 -0
- package/dist/types/types/utils/validate-type.d.ts +4 -4
- package/dist/umd/linked-list-typed.js +2589 -287
- 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/data-structures/base/index.ts +1 -0
- package/src/data-structures/base/iterable-element-base.ts +4 -5
- package/src/data-structures/base/iterable-entry-base.ts +8 -8
- package/src/data-structures/base/linear-base.ts +3 -3
- package/src/data-structures/binary-tree/avl-tree.ts +386 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +596 -247
- package/src/data-structures/binary-tree/binary-tree.ts +956 -81
- package/src/data-structures/binary-tree/bst.ts +840 -35
- package/src/data-structures/binary-tree/red-black-tree.ts +689 -97
- package/src/data-structures/binary-tree/segment-tree.ts +498 -249
- package/src/data-structures/binary-tree/tree-map.ts +3784 -7
- package/src/data-structures/binary-tree/tree-multi-map.ts +3614 -211
- package/src/data-structures/binary-tree/tree-multi-set.ts +2874 -65
- package/src/data-structures/binary-tree/tree-set.ts +3531 -10
- package/src/data-structures/graph/abstract-graph.ts +4 -4
- package/src/data-structures/graph/directed-graph.ts +429 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +393 -59
- package/src/data-structures/hash/hash-map.ts +476 -92
- package/src/data-structures/heap/heap.ts +581 -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 +646 -47
- package/src/data-structures/linked-list/singly-linked-list.ts +596 -68
- package/src/data-structures/linked-list/skip-linked-list.ts +1067 -90
- package/src/data-structures/matrix/matrix.ts +584 -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 +592 -70
- package/src/data-structures/queue/queue.ts +463 -42
- package/src/data-structures/stack/stack.ts +384 -32
- package/src/data-structures/trie/trie.ts +470 -48
- package/src/interfaces/graph.ts +1 -1
- package/src/types/common.ts +2 -2
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
- package/src/types/data-structures/heap/heap.ts +1 -0
- package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
- package/src/types/data-structures/priority-queue/priority-queue.ts +1 -0
- package/src/types/utils/validate-type.ts +4 -4
package/dist/esm/index.mjs
CHANGED
|
@@ -1,55 +1,6 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
-
// src/common/error.ts
|
|
5
|
-
var ERR = {
|
|
6
|
-
// Range / index
|
|
7
|
-
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
|
|
8
|
-
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
|
|
9
|
-
// Type / argument
|
|
10
|
-
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
|
|
11
|
-
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
|
|
12
|
-
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
|
|
13
|
-
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
|
|
14
|
-
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
|
|
15
|
-
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
|
|
16
|
-
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
|
|
17
|
-
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
|
|
18
|
-
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
|
|
19
|
-
// State / operation
|
|
20
|
-
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
|
|
21
|
-
// Matrix
|
|
22
|
-
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
|
|
23
|
-
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
|
|
24
|
-
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
|
|
25
|
-
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
|
|
26
|
-
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// src/common/index.ts
|
|
30
|
-
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
31
|
-
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
32
|
-
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
33
|
-
return DFSOperation2;
|
|
34
|
-
})(DFSOperation || {});
|
|
35
|
-
var Range = class {
|
|
36
|
-
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
37
|
-
this.low = low;
|
|
38
|
-
this.high = high;
|
|
39
|
-
this.includeLow = includeLow;
|
|
40
|
-
this.includeHigh = includeHigh;
|
|
41
|
-
}
|
|
42
|
-
static {
|
|
43
|
-
__name(this, "Range");
|
|
44
|
-
}
|
|
45
|
-
// Determine whether a key is within the range
|
|
46
|
-
isInRange(key, comparator) {
|
|
47
|
-
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
48
|
-
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
49
|
-
return lowCheck && highCheck;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
|
|
53
4
|
// src/data-structures/base/iterable-element-base.ts
|
|
54
5
|
var IterableElementBase = class {
|
|
55
6
|
static {
|
|
@@ -68,7 +19,7 @@ var IterableElementBase = class {
|
|
|
68
19
|
if (options) {
|
|
69
20
|
const { toElementFn } = options;
|
|
70
21
|
if (typeof toElementFn === "function") this._toElementFn = toElementFn;
|
|
71
|
-
else if (toElementFn) throw new TypeError(
|
|
22
|
+
else if (toElementFn) throw new TypeError("toElementFn must be a function type");
|
|
72
23
|
}
|
|
73
24
|
}
|
|
74
25
|
/**
|
|
@@ -231,7 +182,7 @@ var IterableElementBase = class {
|
|
|
231
182
|
acc = initialValue;
|
|
232
183
|
} else {
|
|
233
184
|
const first = iter.next();
|
|
234
|
-
if (first.done) throw new TypeError(
|
|
185
|
+
if (first.done) throw new TypeError("Reduce of empty structure with no initial value");
|
|
235
186
|
acc = first.value;
|
|
236
187
|
index = 1;
|
|
237
188
|
}
|
|
@@ -772,11 +723,58 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
772
723
|
return list;
|
|
773
724
|
}
|
|
774
725
|
/**
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
726
|
+
* Append an element/node to the tail.
|
|
727
|
+
* @remarks Time O(1), Space O(1)
|
|
728
|
+
* @param elementOrNode - Element or node to append.
|
|
729
|
+
* @returns True when appended.
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
* @example
|
|
763
|
+
* // basic SinglyLinkedList creation and push operation
|
|
764
|
+
* // Create a simple SinglyLinkedList with initial values
|
|
765
|
+
* const list = new SinglyLinkedList([1, 2, 3, 4, 5]);
|
|
766
|
+
*
|
|
767
|
+
* // Verify the list maintains insertion order
|
|
768
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
769
|
+
*
|
|
770
|
+
* // Check length
|
|
771
|
+
* console.log(list.length); // 5;
|
|
772
|
+
*
|
|
773
|
+
* // Push a new element to the end
|
|
774
|
+
* list.push(6);
|
|
775
|
+
* console.log(list.length); // 6;
|
|
776
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
777
|
+
*/
|
|
780
778
|
push(elementOrNode) {
|
|
781
779
|
const newNode = this._ensureNode(elementOrNode);
|
|
782
780
|
if (!this.head) {
|
|
@@ -790,10 +788,57 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
790
788
|
return true;
|
|
791
789
|
}
|
|
792
790
|
/**
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
791
|
+
* Remove and return the tail element.
|
|
792
|
+
* @remarks Time O(N), Space O(1)
|
|
793
|
+
* @returns Removed element or undefined.
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
* @example
|
|
827
|
+
* // SinglyLinkedList pop and shift operations
|
|
828
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
829
|
+
*
|
|
830
|
+
* // Pop removes from the end
|
|
831
|
+
* const last = list.pop();
|
|
832
|
+
* console.log(last); // 50;
|
|
833
|
+
*
|
|
834
|
+
* // Shift removes from the beginning
|
|
835
|
+
* const first = list.shift();
|
|
836
|
+
* console.log(first); // 10;
|
|
837
|
+
*
|
|
838
|
+
* // Verify remaining elements
|
|
839
|
+
* console.log([...list]); // [20, 30, 40];
|
|
840
|
+
* console.log(list.length); // 3;
|
|
841
|
+
*/
|
|
797
842
|
pop() {
|
|
798
843
|
if (!this.head) return void 0;
|
|
799
844
|
if (this.head === this.tail) {
|
|
@@ -812,10 +857,47 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
812
857
|
return value;
|
|
813
858
|
}
|
|
814
859
|
/**
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
860
|
+
* Remove and return the head element.
|
|
861
|
+
* @remarks Time O(1), Space O(1)
|
|
862
|
+
* @returns Removed element or undefined.
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
* @example
|
|
896
|
+
* // Remove from the front
|
|
897
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30]);
|
|
898
|
+
* console.log(list.shift()); // 10;
|
|
899
|
+
* console.log(list.length); // 2;
|
|
900
|
+
*/
|
|
819
901
|
shift() {
|
|
820
902
|
if (!this.head) return void 0;
|
|
821
903
|
const removed = this.head;
|
|
@@ -825,11 +907,63 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
825
907
|
return removed.value;
|
|
826
908
|
}
|
|
827
909
|
/**
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
910
|
+
* Prepend an element/node to the head.
|
|
911
|
+
* @remarks Time O(1), Space O(1)
|
|
912
|
+
* @param elementOrNode - Element or node to prepend.
|
|
913
|
+
* @returns True when prepended.
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
* @example
|
|
947
|
+
* // SinglyLinkedList unshift and forward traversal
|
|
948
|
+
* const list = new SinglyLinkedList<number>([20, 30, 40]);
|
|
949
|
+
*
|
|
950
|
+
* // Unshift adds to the beginning
|
|
951
|
+
* list.unshift(10);
|
|
952
|
+
* console.log([...list]); // [10, 20, 30, 40];
|
|
953
|
+
*
|
|
954
|
+
* // Access elements (forward traversal only for singly linked)
|
|
955
|
+
* const second = list.at(1);
|
|
956
|
+
* console.log(second); // 20;
|
|
957
|
+
*
|
|
958
|
+
* // SinglyLinkedList allows forward iteration only
|
|
959
|
+
* const elements: number[] = [];
|
|
960
|
+
* for (const item of list) {
|
|
961
|
+
* elements.push(item);
|
|
962
|
+
* }
|
|
963
|
+
* console.log(elements); // [10, 20, 30, 40];
|
|
964
|
+
*
|
|
965
|
+
* console.log(list.length); // 4;
|
|
966
|
+
*/
|
|
833
967
|
unshift(elementOrNode) {
|
|
834
968
|
const newNode = this._ensureNode(elementOrNode);
|
|
835
969
|
if (!this.head) {
|
|
@@ -885,11 +1019,49 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
885
1019
|
return void 0;
|
|
886
1020
|
}
|
|
887
1021
|
/**
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1022
|
+
* Get the element at a given index.
|
|
1023
|
+
* @remarks Time O(N), Space O(1)
|
|
1024
|
+
* @param index - Zero-based index.
|
|
1025
|
+
* @returns Element or undefined.
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
|
|
1029
|
+
|
|
1030
|
+
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
* @example
|
|
1059
|
+
* // Access element by index
|
|
1060
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c', 'd']);
|
|
1061
|
+
* console.log(list.at(0)); // 'a';
|
|
1062
|
+
* console.log(list.at(2)); // 'c';
|
|
1063
|
+
* console.log(list.at(3)); // 'd';
|
|
1064
|
+
*/
|
|
893
1065
|
at(index) {
|
|
894
1066
|
if (index < 0 || index >= this._length) return void 0;
|
|
895
1067
|
let current = this.head;
|
|
@@ -906,11 +1078,44 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
906
1078
|
return elementNodeOrPredicate instanceof SinglyLinkedListNode;
|
|
907
1079
|
}
|
|
908
1080
|
/**
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1081
|
+
* Get the node reference at a given index.
|
|
1082
|
+
* @remarks Time O(N), Space O(1)
|
|
1083
|
+
* @param index - Zero-based index.
|
|
1084
|
+
* @returns Node or undefined.
|
|
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
|
+
* @example
|
|
1115
|
+
* // Get node at index
|
|
1116
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
1117
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
1118
|
+
*/
|
|
914
1119
|
getNodeAt(index) {
|
|
915
1120
|
if (index < 0 || index >= this._length) return void 0;
|
|
916
1121
|
let current = this.head;
|
|
@@ -918,11 +1123,45 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
918
1123
|
return current;
|
|
919
1124
|
}
|
|
920
1125
|
/**
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1126
|
+
* Delete the element at an index.
|
|
1127
|
+
* @remarks Time O(N), Space O(1)
|
|
1128
|
+
* @param index - Zero-based index.
|
|
1129
|
+
* @returns Removed element or undefined.
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
|
|
1159
|
+
* @example
|
|
1160
|
+
* // Remove by index
|
|
1161
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
1162
|
+
* list.deleteAt(1);
|
|
1163
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
1164
|
+
*/
|
|
926
1165
|
deleteAt(index) {
|
|
927
1166
|
if (index < 0 || index >= this._length) return void 0;
|
|
928
1167
|
if (index === 0) return this.shift();
|
|
@@ -935,11 +1174,45 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
935
1174
|
return value;
|
|
936
1175
|
}
|
|
937
1176
|
/**
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1177
|
+
* Delete the first match by value/node.
|
|
1178
|
+
* @remarks Time O(N), Space O(1)
|
|
1179
|
+
* @param [elementOrNode] - Element or node to remove; if omitted/undefined, nothing happens.
|
|
1180
|
+
* @returns True if removed.
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
* @example
|
|
1211
|
+
* // Remove first occurrence
|
|
1212
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 2]);
|
|
1213
|
+
* list.delete(2);
|
|
1214
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
1215
|
+
*/
|
|
943
1216
|
delete(elementOrNode) {
|
|
944
1217
|
if (elementOrNode === void 0 || !this.head) return false;
|
|
945
1218
|
const node = this.isNode(elementOrNode) ? elementOrNode : this.getNode(elementOrNode);
|
|
@@ -956,12 +1229,46 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
956
1229
|
return true;
|
|
957
1230
|
}
|
|
958
1231
|
/**
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1232
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
1233
|
+
* @remarks Time O(N), Space O(1)
|
|
1234
|
+
* @param index - Zero-based index.
|
|
1235
|
+
* @param newElementOrNode - Element or node to insert.
|
|
1236
|
+
* @returns True if inserted.
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
* @example
|
|
1267
|
+
* // Insert at index
|
|
1268
|
+
* const list = new SinglyLinkedList<number>([1, 3]);
|
|
1269
|
+
* list.addAt(1, 2);
|
|
1270
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
1271
|
+
*/
|
|
965
1272
|
addAt(index, newElementOrNode) {
|
|
966
1273
|
if (index < 0 || index > this._length) return false;
|
|
967
1274
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -987,28 +1294,133 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
987
1294
|
return true;
|
|
988
1295
|
}
|
|
989
1296
|
/**
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1297
|
+
* Check whether the list is empty.
|
|
1298
|
+
* @remarks Time O(1), Space O(1)
|
|
1299
|
+
* @returns True if length is 0.
|
|
1300
|
+
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
|
|
1304
|
+
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
|
|
1319
|
+
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
|
|
1330
|
+
* @example
|
|
1331
|
+
* // Check empty
|
|
1332
|
+
* console.log(new SinglyLinkedList().isEmpty()); // true;
|
|
1333
|
+
*/
|
|
994
1334
|
isEmpty() {
|
|
995
1335
|
return this._length === 0;
|
|
996
1336
|
}
|
|
997
1337
|
/**
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1338
|
+
* Remove all nodes and reset length.
|
|
1339
|
+
* @remarks Time O(N), Space O(1)
|
|
1340
|
+
* @returns void
|
|
1341
|
+
|
|
1342
|
+
|
|
1343
|
+
|
|
1344
|
+
|
|
1345
|
+
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
|
|
1366
|
+
|
|
1367
|
+
|
|
1368
|
+
|
|
1369
|
+
|
|
1370
|
+
|
|
1371
|
+
* @example
|
|
1372
|
+
* // Remove all
|
|
1373
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1374
|
+
* list.clear();
|
|
1375
|
+
* console.log(list.isEmpty()); // true;
|
|
1376
|
+
*/
|
|
1002
1377
|
clear() {
|
|
1003
1378
|
this._head = void 0;
|
|
1004
1379
|
this._tail = void 0;
|
|
1005
1380
|
this._length = 0;
|
|
1006
1381
|
}
|
|
1007
1382
|
/**
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1383
|
+
* Reverse the list in place.
|
|
1384
|
+
* @remarks Time O(N), Space O(1)
|
|
1385
|
+
* @returns This list.
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
|
|
1399
|
+
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
|
|
1418
|
+
* @example
|
|
1419
|
+
* // Reverse the list in-place
|
|
1420
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4]);
|
|
1421
|
+
* list.reverse();
|
|
1422
|
+
* console.log([...list]); // [4, 3, 2, 1];
|
|
1423
|
+
*/
|
|
1012
1424
|
reverse() {
|
|
1013
1425
|
if (!this.head || this.head === this.tail) return this;
|
|
1014
1426
|
let prev;
|
|
@@ -1183,22 +1595,106 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1183
1595
|
return false;
|
|
1184
1596
|
}
|
|
1185
1597
|
/**
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1598
|
+
* Deep clone this list (values are copied by reference).
|
|
1599
|
+
* @remarks Time O(N), Space O(N)
|
|
1600
|
+
* @returns A new list with the same element sequence.
|
|
1601
|
+
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
|
|
1610
|
+
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
|
|
1614
|
+
|
|
1615
|
+
|
|
1616
|
+
|
|
1617
|
+
|
|
1618
|
+
|
|
1619
|
+
|
|
1620
|
+
|
|
1621
|
+
|
|
1622
|
+
|
|
1623
|
+
|
|
1624
|
+
|
|
1625
|
+
|
|
1626
|
+
|
|
1627
|
+
|
|
1628
|
+
|
|
1629
|
+
|
|
1630
|
+
|
|
1631
|
+
* @example
|
|
1632
|
+
* // Deep copy
|
|
1633
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1634
|
+
* const copy = list.clone();
|
|
1635
|
+
* copy.pop();
|
|
1636
|
+
* console.log(list.length); // 3;
|
|
1637
|
+
* console.log(copy.length); // 2;
|
|
1638
|
+
*/
|
|
1190
1639
|
clone() {
|
|
1191
1640
|
const out = this._createInstance();
|
|
1192
1641
|
for (const v of this) out.push(v);
|
|
1193
1642
|
return out;
|
|
1194
1643
|
}
|
|
1195
1644
|
/**
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1645
|
+
* Filter values into a new list of the same class.
|
|
1646
|
+
* @remarks Time O(N), Space O(N)
|
|
1647
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
1648
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1649
|
+
* @returns A new list with kept values.
|
|
1650
|
+
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
|
|
1656
|
+
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
|
|
1677
|
+
|
|
1678
|
+
|
|
1679
|
+
|
|
1680
|
+
|
|
1681
|
+
|
|
1682
|
+
* @example
|
|
1683
|
+
* // SinglyLinkedList filter and map operations
|
|
1684
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
1685
|
+
*
|
|
1686
|
+
* // Filter even numbers
|
|
1687
|
+
* const filtered = list.filter(value => value % 2 === 0);
|
|
1688
|
+
* console.log(filtered.length); // 2;
|
|
1689
|
+
*
|
|
1690
|
+
* // Map to double values
|
|
1691
|
+
* const doubled = list.map(value => value * 2);
|
|
1692
|
+
* console.log(doubled.length); // 5;
|
|
1693
|
+
*
|
|
1694
|
+
* // Use reduce to sum
|
|
1695
|
+
* const sum = list.reduce((acc, value) => acc + value, 0);
|
|
1696
|
+
* console.log(sum); // 15;
|
|
1697
|
+
*/
|
|
1202
1698
|
filter(callback, thisArg) {
|
|
1203
1699
|
const out = this._createInstance();
|
|
1204
1700
|
let index = 0;
|
|
@@ -1222,15 +1718,52 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1222
1718
|
return out;
|
|
1223
1719
|
}
|
|
1224
1720
|
/**
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1721
|
+
* Map values into a new list (possibly different element type).
|
|
1722
|
+
* @remarks Time O(N), Space O(N)
|
|
1723
|
+
* @template EM
|
|
1724
|
+
* @template RM
|
|
1725
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
1726
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
1727
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1728
|
+
* @returns A new SinglyLinkedList with mapped values.
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
|
|
1733
|
+
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
|
|
1738
|
+
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
|
|
1743
|
+
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
|
|
1748
|
+
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
|
|
1752
|
+
|
|
1753
|
+
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
|
|
1757
|
+
|
|
1758
|
+
|
|
1759
|
+
|
|
1760
|
+
|
|
1761
|
+
* @example
|
|
1762
|
+
* // Transform elements
|
|
1763
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1764
|
+
* const doubled = list.map(n => n * 2);
|
|
1765
|
+
* console.log([...doubled]); // [2, 4, 6];
|
|
1766
|
+
*/
|
|
1234
1767
|
map(callback, options, thisArg) {
|
|
1235
1768
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1236
1769
|
let index = 0;
|
|
@@ -1506,11 +2039,58 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1506
2039
|
return elementNodeOrPredicate instanceof DoublyLinkedListNode;
|
|
1507
2040
|
}
|
|
1508
2041
|
/**
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
2042
|
+
* Append an element/node to the tail.
|
|
2043
|
+
* @remarks Time O(1), Space O(1)
|
|
2044
|
+
* @param elementOrNode - Element or node to append.
|
|
2045
|
+
* @returns True when appended.
|
|
2046
|
+
|
|
2047
|
+
|
|
2048
|
+
|
|
2049
|
+
|
|
2050
|
+
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
|
|
2054
|
+
|
|
2055
|
+
|
|
2056
|
+
|
|
2057
|
+
|
|
2058
|
+
|
|
2059
|
+
|
|
2060
|
+
|
|
2061
|
+
|
|
2062
|
+
|
|
2063
|
+
|
|
2064
|
+
|
|
2065
|
+
|
|
2066
|
+
|
|
2067
|
+
|
|
2068
|
+
|
|
2069
|
+
|
|
2070
|
+
|
|
2071
|
+
|
|
2072
|
+
|
|
2073
|
+
|
|
2074
|
+
|
|
2075
|
+
|
|
2076
|
+
|
|
2077
|
+
|
|
2078
|
+
* @example
|
|
2079
|
+
* // basic DoublyLinkedList creation and push operation
|
|
2080
|
+
* // Create a simple DoublyLinkedList with initial values
|
|
2081
|
+
* const list = new DoublyLinkedList([1, 2, 3, 4, 5]);
|
|
2082
|
+
*
|
|
2083
|
+
* // Verify the list maintains insertion order
|
|
2084
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
2085
|
+
*
|
|
2086
|
+
* // Check length
|
|
2087
|
+
* console.log(list.length); // 5;
|
|
2088
|
+
*
|
|
2089
|
+
* // Push a new element to the end
|
|
2090
|
+
* list.push(6);
|
|
2091
|
+
* console.log(list.length); // 6;
|
|
2092
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
2093
|
+
*/
|
|
1514
2094
|
push(elementOrNode) {
|
|
1515
2095
|
const newNode = this._ensureNode(elementOrNode);
|
|
1516
2096
|
if (!this.head) {
|
|
@@ -1526,10 +2106,57 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1526
2106
|
return true;
|
|
1527
2107
|
}
|
|
1528
2108
|
/**
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
2109
|
+
* Remove and return the tail element.
|
|
2110
|
+
* @remarks Time O(1), Space O(1)
|
|
2111
|
+
* @returns Removed element or undefined.
|
|
2112
|
+
|
|
2113
|
+
|
|
2114
|
+
|
|
2115
|
+
|
|
2116
|
+
|
|
2117
|
+
|
|
2118
|
+
|
|
2119
|
+
|
|
2120
|
+
|
|
2121
|
+
|
|
2122
|
+
|
|
2123
|
+
|
|
2124
|
+
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
|
|
2128
|
+
|
|
2129
|
+
|
|
2130
|
+
|
|
2131
|
+
|
|
2132
|
+
|
|
2133
|
+
|
|
2134
|
+
|
|
2135
|
+
|
|
2136
|
+
|
|
2137
|
+
|
|
2138
|
+
|
|
2139
|
+
|
|
2140
|
+
|
|
2141
|
+
|
|
2142
|
+
|
|
2143
|
+
|
|
2144
|
+
* @example
|
|
2145
|
+
* // DoublyLinkedList pop and shift operations
|
|
2146
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
2147
|
+
*
|
|
2148
|
+
* // Pop removes from the end
|
|
2149
|
+
* const last = list.pop();
|
|
2150
|
+
* console.log(last); // 50;
|
|
2151
|
+
*
|
|
2152
|
+
* // Shift removes from the beginning
|
|
2153
|
+
* const first = list.shift();
|
|
2154
|
+
* console.log(first); // 10;
|
|
2155
|
+
*
|
|
2156
|
+
* // Verify remaining elements
|
|
2157
|
+
* console.log([...list]); // [20, 30, 40];
|
|
2158
|
+
* console.log(list.length); // 3;
|
|
2159
|
+
*/
|
|
1533
2160
|
pop() {
|
|
1534
2161
|
if (!this.tail) return void 0;
|
|
1535
2162
|
const removed = this.tail;
|
|
@@ -1544,10 +2171,47 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1544
2171
|
return removed.value;
|
|
1545
2172
|
}
|
|
1546
2173
|
/**
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
2174
|
+
* Remove and return the head element.
|
|
2175
|
+
* @remarks Time O(1), Space O(1)
|
|
2176
|
+
* @returns Removed element or undefined.
|
|
2177
|
+
|
|
2178
|
+
|
|
2179
|
+
|
|
2180
|
+
|
|
2181
|
+
|
|
2182
|
+
|
|
2183
|
+
|
|
2184
|
+
|
|
2185
|
+
|
|
2186
|
+
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
|
|
2190
|
+
|
|
2191
|
+
|
|
2192
|
+
|
|
2193
|
+
|
|
2194
|
+
|
|
2195
|
+
|
|
2196
|
+
|
|
2197
|
+
|
|
2198
|
+
|
|
2199
|
+
|
|
2200
|
+
|
|
2201
|
+
|
|
2202
|
+
|
|
2203
|
+
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
|
|
2207
|
+
|
|
2208
|
+
|
|
2209
|
+
* @example
|
|
2210
|
+
* // Remove from the front
|
|
2211
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
2212
|
+
* console.log(list.shift()); // 10;
|
|
2213
|
+
* console.log(list.first); // 20;
|
|
2214
|
+
*/
|
|
1551
2215
|
shift() {
|
|
1552
2216
|
if (!this.head) return void 0;
|
|
1553
2217
|
const removed = this.head;
|
|
@@ -1562,11 +2226,48 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1562
2226
|
return removed.value;
|
|
1563
2227
|
}
|
|
1564
2228
|
/**
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
2229
|
+
* Prepend an element/node to the head.
|
|
2230
|
+
* @remarks Time O(1), Space O(1)
|
|
2231
|
+
* @param elementOrNode - Element or node to prepend.
|
|
2232
|
+
* @returns True when prepended.
|
|
2233
|
+
|
|
2234
|
+
|
|
2235
|
+
|
|
2236
|
+
|
|
2237
|
+
|
|
2238
|
+
|
|
2239
|
+
|
|
2240
|
+
|
|
2241
|
+
|
|
2242
|
+
|
|
2243
|
+
|
|
2244
|
+
|
|
2245
|
+
|
|
2246
|
+
|
|
2247
|
+
|
|
2248
|
+
|
|
2249
|
+
|
|
2250
|
+
|
|
2251
|
+
|
|
2252
|
+
|
|
2253
|
+
|
|
2254
|
+
|
|
2255
|
+
|
|
2256
|
+
|
|
2257
|
+
|
|
2258
|
+
|
|
2259
|
+
|
|
2260
|
+
|
|
2261
|
+
|
|
2262
|
+
|
|
2263
|
+
|
|
2264
|
+
|
|
2265
|
+
* @example
|
|
2266
|
+
* // Add to the front
|
|
2267
|
+
* const list = new DoublyLinkedList<number>([2, 3]);
|
|
2268
|
+
* list.unshift(1);
|
|
2269
|
+
* console.log([...list]); // [1, 2, 3];
|
|
2270
|
+
*/
|
|
1570
2271
|
unshift(elementOrNode) {
|
|
1571
2272
|
const newNode = this._ensureNode(elementOrNode);
|
|
1572
2273
|
if (!this.head) {
|
|
@@ -1610,11 +2311,48 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1610
2311
|
return ans;
|
|
1611
2312
|
}
|
|
1612
2313
|
/**
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
2314
|
+
* Get the element at a given index.
|
|
2315
|
+
* @remarks Time O(N), Space O(1)
|
|
2316
|
+
* @param index - Zero-based index.
|
|
2317
|
+
* @returns Element or undefined.
|
|
2318
|
+
|
|
2319
|
+
|
|
2320
|
+
|
|
2321
|
+
|
|
2322
|
+
|
|
2323
|
+
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
|
|
2330
|
+
|
|
2331
|
+
|
|
2332
|
+
|
|
2333
|
+
|
|
2334
|
+
|
|
2335
|
+
|
|
2336
|
+
|
|
2337
|
+
|
|
2338
|
+
|
|
2339
|
+
|
|
2340
|
+
|
|
2341
|
+
|
|
2342
|
+
|
|
2343
|
+
|
|
2344
|
+
|
|
2345
|
+
|
|
2346
|
+
|
|
2347
|
+
|
|
2348
|
+
|
|
2349
|
+
|
|
2350
|
+
* @example
|
|
2351
|
+
* // Access by index
|
|
2352
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2353
|
+
* console.log(list.at(1)); // 'b';
|
|
2354
|
+
* console.log(list.at(2)); // 'c';
|
|
2355
|
+
*/
|
|
1618
2356
|
at(index) {
|
|
1619
2357
|
if (index < 0 || index >= this._length) return void 0;
|
|
1620
2358
|
let current = this.head;
|
|
@@ -1622,11 +2360,44 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1622
2360
|
return current?.value;
|
|
1623
2361
|
}
|
|
1624
2362
|
/**
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
2363
|
+
* Get the node reference at a given index.
|
|
2364
|
+
* @remarks Time O(N), Space O(1)
|
|
2365
|
+
* @param index - Zero-based index.
|
|
2366
|
+
* @returns Node or undefined.
|
|
2367
|
+
|
|
2368
|
+
|
|
2369
|
+
|
|
2370
|
+
|
|
2371
|
+
|
|
2372
|
+
|
|
2373
|
+
|
|
2374
|
+
|
|
2375
|
+
|
|
2376
|
+
|
|
2377
|
+
|
|
2378
|
+
|
|
2379
|
+
|
|
2380
|
+
|
|
2381
|
+
|
|
2382
|
+
|
|
2383
|
+
|
|
2384
|
+
|
|
2385
|
+
|
|
2386
|
+
|
|
2387
|
+
|
|
2388
|
+
|
|
2389
|
+
|
|
2390
|
+
|
|
2391
|
+
|
|
2392
|
+
|
|
2393
|
+
|
|
2394
|
+
|
|
2395
|
+
|
|
2396
|
+
* @example
|
|
2397
|
+
* // Get node at index
|
|
2398
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2399
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
2400
|
+
*/
|
|
1630
2401
|
getNodeAt(index) {
|
|
1631
2402
|
if (index < 0 || index >= this._length) return void 0;
|
|
1632
2403
|
let current = this.head;
|
|
@@ -1665,12 +2436,46 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1665
2436
|
return void 0;
|
|
1666
2437
|
}
|
|
1667
2438
|
/**
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
2439
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
2440
|
+
* @remarks Time O(N), Space O(1)
|
|
2441
|
+
* @param index - Zero-based index.
|
|
2442
|
+
* @param newElementOrNode - Element or node to insert.
|
|
2443
|
+
* @returns True if inserted.
|
|
2444
|
+
|
|
2445
|
+
|
|
2446
|
+
|
|
2447
|
+
|
|
2448
|
+
|
|
2449
|
+
|
|
2450
|
+
|
|
2451
|
+
|
|
2452
|
+
|
|
2453
|
+
|
|
2454
|
+
|
|
2455
|
+
|
|
2456
|
+
|
|
2457
|
+
|
|
2458
|
+
|
|
2459
|
+
|
|
2460
|
+
|
|
2461
|
+
|
|
2462
|
+
|
|
2463
|
+
|
|
2464
|
+
|
|
2465
|
+
|
|
2466
|
+
|
|
2467
|
+
|
|
2468
|
+
|
|
2469
|
+
|
|
2470
|
+
|
|
2471
|
+
|
|
2472
|
+
|
|
2473
|
+
* @example
|
|
2474
|
+
* // Insert at position
|
|
2475
|
+
* const list = new DoublyLinkedList<number>([1, 3]);
|
|
2476
|
+
* list.addAt(1, 2);
|
|
2477
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
2478
|
+
*/
|
|
1674
2479
|
addAt(index, newElementOrNode) {
|
|
1675
2480
|
if (index < 0 || index > this._length) return false;
|
|
1676
2481
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -1737,11 +2542,45 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1737
2542
|
return true;
|
|
1738
2543
|
}
|
|
1739
2544
|
/**
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
2545
|
+
* Delete the element at an index.
|
|
2546
|
+
* @remarks Time O(N), Space O(1)
|
|
2547
|
+
* @param index - Zero-based index.
|
|
2548
|
+
* @returns Removed element or undefined.
|
|
2549
|
+
|
|
2550
|
+
|
|
2551
|
+
|
|
2552
|
+
|
|
2553
|
+
|
|
2554
|
+
|
|
2555
|
+
|
|
2556
|
+
|
|
2557
|
+
|
|
2558
|
+
|
|
2559
|
+
|
|
2560
|
+
|
|
2561
|
+
|
|
2562
|
+
|
|
2563
|
+
|
|
2564
|
+
|
|
2565
|
+
|
|
2566
|
+
|
|
2567
|
+
|
|
2568
|
+
|
|
2569
|
+
|
|
2570
|
+
|
|
2571
|
+
|
|
2572
|
+
|
|
2573
|
+
|
|
2574
|
+
|
|
2575
|
+
|
|
2576
|
+
|
|
2577
|
+
|
|
2578
|
+
* @example
|
|
2579
|
+
* // Remove by index
|
|
2580
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2581
|
+
* list.deleteAt(1);
|
|
2582
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
2583
|
+
*/
|
|
1745
2584
|
deleteAt(index) {
|
|
1746
2585
|
if (index < 0 || index >= this._length) return;
|
|
1747
2586
|
if (index === 0) return this.shift();
|
|
@@ -1755,11 +2594,45 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1755
2594
|
return removedNode.value;
|
|
1756
2595
|
}
|
|
1757
2596
|
/**
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
2597
|
+
* Delete the first match by value/node.
|
|
2598
|
+
* @remarks Time O(N), Space O(1)
|
|
2599
|
+
* @param [elementOrNode] - Element or node to remove.
|
|
2600
|
+
* @returns True if removed.
|
|
2601
|
+
|
|
2602
|
+
|
|
2603
|
+
|
|
2604
|
+
|
|
2605
|
+
|
|
2606
|
+
|
|
2607
|
+
|
|
2608
|
+
|
|
2609
|
+
|
|
2610
|
+
|
|
2611
|
+
|
|
2612
|
+
|
|
2613
|
+
|
|
2614
|
+
|
|
2615
|
+
|
|
2616
|
+
|
|
2617
|
+
|
|
2618
|
+
|
|
2619
|
+
|
|
2620
|
+
|
|
2621
|
+
|
|
2622
|
+
|
|
2623
|
+
|
|
2624
|
+
|
|
2625
|
+
|
|
2626
|
+
|
|
2627
|
+
|
|
2628
|
+
|
|
2629
|
+
|
|
2630
|
+
* @example
|
|
2631
|
+
* // Remove first occurrence
|
|
2632
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 2]);
|
|
2633
|
+
* list.delete(2);
|
|
2634
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
2635
|
+
*/
|
|
1763
2636
|
delete(elementOrNode) {
|
|
1764
2637
|
const node = this.getNode(elementOrNode);
|
|
1765
2638
|
if (!node) return false;
|
|
@@ -1775,29 +2648,131 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1775
2648
|
return true;
|
|
1776
2649
|
}
|
|
1777
2650
|
/**
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
2651
|
+
* Check whether the list is empty.
|
|
2652
|
+
* @remarks Time O(1), Space O(1)
|
|
2653
|
+
* @returns True if length is 0.
|
|
2654
|
+
|
|
2655
|
+
|
|
2656
|
+
|
|
2657
|
+
|
|
2658
|
+
|
|
2659
|
+
|
|
2660
|
+
|
|
2661
|
+
|
|
2662
|
+
|
|
2663
|
+
|
|
2664
|
+
|
|
2665
|
+
|
|
2666
|
+
|
|
2667
|
+
|
|
2668
|
+
|
|
2669
|
+
|
|
2670
|
+
|
|
2671
|
+
|
|
2672
|
+
|
|
2673
|
+
|
|
2674
|
+
|
|
2675
|
+
|
|
2676
|
+
|
|
2677
|
+
|
|
2678
|
+
|
|
2679
|
+
|
|
2680
|
+
|
|
2681
|
+
|
|
2682
|
+
|
|
2683
|
+
|
|
2684
|
+
* @example
|
|
2685
|
+
* // Check empty
|
|
2686
|
+
* console.log(new DoublyLinkedList().isEmpty()); // true;
|
|
2687
|
+
*/
|
|
1782
2688
|
isEmpty() {
|
|
1783
2689
|
return this._length === 0;
|
|
1784
2690
|
}
|
|
1785
2691
|
/**
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
2692
|
+
* Remove all nodes and reset length.
|
|
2693
|
+
* @remarks Time O(N), Space O(1)
|
|
2694
|
+
* @returns void
|
|
2695
|
+
|
|
2696
|
+
|
|
2697
|
+
|
|
2698
|
+
|
|
2699
|
+
|
|
2700
|
+
|
|
2701
|
+
|
|
2702
|
+
|
|
2703
|
+
|
|
2704
|
+
|
|
2705
|
+
|
|
2706
|
+
|
|
2707
|
+
|
|
2708
|
+
|
|
2709
|
+
|
|
2710
|
+
|
|
2711
|
+
|
|
2712
|
+
|
|
2713
|
+
|
|
2714
|
+
|
|
2715
|
+
|
|
2716
|
+
|
|
2717
|
+
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
|
|
2721
|
+
|
|
2722
|
+
|
|
2723
|
+
|
|
2724
|
+
|
|
2725
|
+
* @example
|
|
2726
|
+
* // Remove all
|
|
2727
|
+
* const list = new DoublyLinkedList<number>([1, 2]);
|
|
2728
|
+
* list.clear();
|
|
2729
|
+
* console.log(list.isEmpty()); // true;
|
|
2730
|
+
*/
|
|
1790
2731
|
clear() {
|
|
1791
2732
|
this._head = void 0;
|
|
1792
2733
|
this._tail = void 0;
|
|
1793
2734
|
this._length = 0;
|
|
1794
2735
|
}
|
|
1795
2736
|
/**
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2737
|
+
* Find the first value matching a predicate scanning forward.
|
|
2738
|
+
* @remarks Time O(N), Space O(1)
|
|
2739
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2740
|
+
* @returns Matched value or undefined.
|
|
2741
|
+
|
|
2742
|
+
|
|
2743
|
+
|
|
2744
|
+
|
|
2745
|
+
|
|
2746
|
+
|
|
2747
|
+
|
|
2748
|
+
|
|
2749
|
+
|
|
2750
|
+
|
|
2751
|
+
|
|
2752
|
+
|
|
2753
|
+
|
|
2754
|
+
|
|
2755
|
+
|
|
2756
|
+
|
|
2757
|
+
|
|
2758
|
+
|
|
2759
|
+
|
|
2760
|
+
|
|
2761
|
+
|
|
2762
|
+
|
|
2763
|
+
|
|
2764
|
+
|
|
2765
|
+
|
|
2766
|
+
|
|
2767
|
+
|
|
2768
|
+
|
|
2769
|
+
|
|
2770
|
+
* @example
|
|
2771
|
+
* // Search with predicate
|
|
2772
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
2773
|
+
* const found = list.search(node => node.value > 15);
|
|
2774
|
+
* console.log(found); // 20;
|
|
2775
|
+
*/
|
|
1801
2776
|
search(elementNodeOrPredicate) {
|
|
1802
2777
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1803
2778
|
let current = this.head;
|
|
@@ -1808,11 +2783,46 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1808
2783
|
return void 0;
|
|
1809
2784
|
}
|
|
1810
2785
|
/**
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2786
|
+
* Find the first value matching a predicate scanning backward.
|
|
2787
|
+
* @remarks Time O(N), Space O(1)
|
|
2788
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2789
|
+
* @returns Matched value or undefined.
|
|
2790
|
+
|
|
2791
|
+
|
|
2792
|
+
|
|
2793
|
+
|
|
2794
|
+
|
|
2795
|
+
|
|
2796
|
+
|
|
2797
|
+
|
|
2798
|
+
|
|
2799
|
+
|
|
2800
|
+
|
|
2801
|
+
|
|
2802
|
+
|
|
2803
|
+
|
|
2804
|
+
|
|
2805
|
+
|
|
2806
|
+
|
|
2807
|
+
|
|
2808
|
+
|
|
2809
|
+
|
|
2810
|
+
|
|
2811
|
+
|
|
2812
|
+
|
|
2813
|
+
|
|
2814
|
+
|
|
2815
|
+
|
|
2816
|
+
|
|
2817
|
+
|
|
2818
|
+
|
|
2819
|
+
* @example
|
|
2820
|
+
* // Find value scanning from tail
|
|
2821
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4]);
|
|
2822
|
+
* // getBackward scans from tail to head, returns first match
|
|
2823
|
+
* const found = list.getBackward(node => node.value < 4);
|
|
2824
|
+
* console.log(found); // 3;
|
|
2825
|
+
*/
|
|
1816
2826
|
getBackward(elementNodeOrPredicate) {
|
|
1817
2827
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1818
2828
|
let current = this.tail;
|
|
@@ -1823,10 +2833,47 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1823
2833
|
return void 0;
|
|
1824
2834
|
}
|
|
1825
2835
|
/**
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
2836
|
+
* Reverse the list in place.
|
|
2837
|
+
* @remarks Time O(N), Space O(1)
|
|
2838
|
+
* @returns This list.
|
|
2839
|
+
|
|
2840
|
+
|
|
2841
|
+
|
|
2842
|
+
|
|
2843
|
+
|
|
2844
|
+
|
|
2845
|
+
|
|
2846
|
+
|
|
2847
|
+
|
|
2848
|
+
|
|
2849
|
+
|
|
2850
|
+
|
|
2851
|
+
|
|
2852
|
+
|
|
2853
|
+
|
|
2854
|
+
|
|
2855
|
+
|
|
2856
|
+
|
|
2857
|
+
|
|
2858
|
+
|
|
2859
|
+
|
|
2860
|
+
|
|
2861
|
+
|
|
2862
|
+
|
|
2863
|
+
|
|
2864
|
+
|
|
2865
|
+
|
|
2866
|
+
|
|
2867
|
+
|
|
2868
|
+
|
|
2869
|
+
|
|
2870
|
+
|
|
2871
|
+
* @example
|
|
2872
|
+
* // Reverse in-place
|
|
2873
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2874
|
+
* list.reverse();
|
|
2875
|
+
* console.log([...list]); // [3, 2, 1];
|
|
2876
|
+
*/
|
|
1830
2877
|
reverse() {
|
|
1831
2878
|
let current = this.head;
|
|
1832
2879
|
[this._head, this._tail] = [this.tail, this.head];
|
|
@@ -1848,22 +2895,95 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1848
2895
|
return this;
|
|
1849
2896
|
}
|
|
1850
2897
|
/**
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
2898
|
+
* Deep clone this list (values are copied by reference).
|
|
2899
|
+
* @remarks Time O(N), Space O(N)
|
|
2900
|
+
* @returns A new list with the same element sequence.
|
|
2901
|
+
|
|
2902
|
+
|
|
2903
|
+
|
|
2904
|
+
|
|
2905
|
+
|
|
2906
|
+
|
|
2907
|
+
|
|
2908
|
+
|
|
2909
|
+
|
|
2910
|
+
|
|
2911
|
+
|
|
2912
|
+
|
|
2913
|
+
|
|
2914
|
+
|
|
2915
|
+
|
|
2916
|
+
|
|
2917
|
+
|
|
2918
|
+
|
|
2919
|
+
|
|
2920
|
+
|
|
2921
|
+
|
|
2922
|
+
|
|
2923
|
+
|
|
2924
|
+
|
|
2925
|
+
|
|
2926
|
+
|
|
2927
|
+
|
|
2928
|
+
|
|
2929
|
+
|
|
2930
|
+
|
|
2931
|
+
* @example
|
|
2932
|
+
* // Deep copy
|
|
2933
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2934
|
+
* const copy = list.clone();
|
|
2935
|
+
* copy.pop();
|
|
2936
|
+
* console.log(list.length); // 3;
|
|
2937
|
+
*/
|
|
1855
2938
|
clone() {
|
|
1856
2939
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1857
2940
|
for (const v of this) out.push(v);
|
|
1858
2941
|
return out;
|
|
1859
2942
|
}
|
|
1860
2943
|
/**
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2944
|
+
* Filter values into a new list of the same class.
|
|
2945
|
+
* @remarks Time O(N), Space O(N)
|
|
2946
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
2947
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
2948
|
+
* @returns A new list with kept values.
|
|
2949
|
+
|
|
2950
|
+
|
|
2951
|
+
|
|
2952
|
+
|
|
2953
|
+
|
|
2954
|
+
|
|
2955
|
+
|
|
2956
|
+
|
|
2957
|
+
|
|
2958
|
+
|
|
2959
|
+
|
|
2960
|
+
|
|
2961
|
+
|
|
2962
|
+
|
|
2963
|
+
|
|
2964
|
+
|
|
2965
|
+
|
|
2966
|
+
|
|
2967
|
+
|
|
2968
|
+
|
|
2969
|
+
|
|
2970
|
+
|
|
2971
|
+
|
|
2972
|
+
|
|
2973
|
+
|
|
2974
|
+
|
|
2975
|
+
|
|
2976
|
+
|
|
2977
|
+
|
|
2978
|
+
|
|
2979
|
+
|
|
2980
|
+
|
|
2981
|
+
* @example
|
|
2982
|
+
* // Filter elements
|
|
2983
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
2984
|
+
* const evens = list.filter(n => n % 2 === 0);
|
|
2985
|
+
* console.log([...evens]); // [2, 4];
|
|
2986
|
+
*/
|
|
1867
2987
|
filter(callback, thisArg) {
|
|
1868
2988
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1869
2989
|
let index = 0;
|
|
@@ -1887,15 +3007,61 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1887
3007
|
return out;
|
|
1888
3008
|
}
|
|
1889
3009
|
/**
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
3010
|
+
* Map values into a new list (possibly different element type).
|
|
3011
|
+
* @remarks Time O(N), Space O(N)
|
|
3012
|
+
* @template EM
|
|
3013
|
+
* @template RM
|
|
3014
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
3015
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
3016
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
3017
|
+
* @returns A new DoublyLinkedList with mapped values.
|
|
3018
|
+
|
|
3019
|
+
|
|
3020
|
+
|
|
3021
|
+
|
|
3022
|
+
|
|
3023
|
+
|
|
3024
|
+
|
|
3025
|
+
|
|
3026
|
+
|
|
3027
|
+
|
|
3028
|
+
|
|
3029
|
+
|
|
3030
|
+
|
|
3031
|
+
|
|
3032
|
+
|
|
3033
|
+
|
|
3034
|
+
|
|
3035
|
+
|
|
3036
|
+
|
|
3037
|
+
|
|
3038
|
+
|
|
3039
|
+
|
|
3040
|
+
|
|
3041
|
+
|
|
3042
|
+
|
|
3043
|
+
|
|
3044
|
+
|
|
3045
|
+
|
|
3046
|
+
|
|
3047
|
+
|
|
3048
|
+
|
|
3049
|
+
|
|
3050
|
+
* @example
|
|
3051
|
+
* // DoublyLinkedList for...of iteration and map operation
|
|
3052
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
3053
|
+
*
|
|
3054
|
+
* // Iterate through list
|
|
3055
|
+
* const doubled = list.map(value => value * 2);
|
|
3056
|
+
* console.log(doubled.length); // 5;
|
|
3057
|
+
*
|
|
3058
|
+
* // Use for...of loop
|
|
3059
|
+
* const result: number[] = [];
|
|
3060
|
+
* for (const item of list) {
|
|
3061
|
+
* result.push(item);
|
|
3062
|
+
* }
|
|
3063
|
+
* console.log(result); // [1, 2, 3, 4, 5];
|
|
3064
|
+
*/
|
|
1899
3065
|
map(callback, options, thisArg) {
|
|
1900
3066
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1901
3067
|
let index = 0;
|
|
@@ -1984,6 +3150,237 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1984
3150
|
}
|
|
1985
3151
|
};
|
|
1986
3152
|
|
|
3153
|
+
// src/common/error.ts
|
|
3154
|
+
var ERR = {
|
|
3155
|
+
// Range / index
|
|
3156
|
+
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
|
|
3157
|
+
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
|
|
3158
|
+
// Type / argument
|
|
3159
|
+
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
|
|
3160
|
+
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
|
|
3161
|
+
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
|
|
3162
|
+
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
|
|
3163
|
+
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
|
|
3164
|
+
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
|
|
3165
|
+
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
|
|
3166
|
+
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
|
|
3167
|
+
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
|
|
3168
|
+
// State / operation
|
|
3169
|
+
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
|
|
3170
|
+
// Matrix
|
|
3171
|
+
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
|
|
3172
|
+
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
|
|
3173
|
+
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
|
|
3174
|
+
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
|
|
3175
|
+
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
|
|
3176
|
+
};
|
|
3177
|
+
|
|
3178
|
+
// src/common/index.ts
|
|
3179
|
+
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
3180
|
+
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
3181
|
+
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
3182
|
+
return DFSOperation2;
|
|
3183
|
+
})(DFSOperation || {});
|
|
3184
|
+
var Range = class {
|
|
3185
|
+
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
3186
|
+
this.low = low;
|
|
3187
|
+
this.high = high;
|
|
3188
|
+
this.includeLow = includeLow;
|
|
3189
|
+
this.includeHigh = includeHigh;
|
|
3190
|
+
}
|
|
3191
|
+
static {
|
|
3192
|
+
__name(this, "Range");
|
|
3193
|
+
}
|
|
3194
|
+
// Determine whether a key is within the range
|
|
3195
|
+
isInRange(key, comparator) {
|
|
3196
|
+
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
3197
|
+
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
3198
|
+
return lowCheck && highCheck;
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3201
|
+
|
|
3202
|
+
// src/data-structures/base/iterable-entry-base.ts
|
|
3203
|
+
var IterableEntryBase = class {
|
|
3204
|
+
static {
|
|
3205
|
+
__name(this, "IterableEntryBase");
|
|
3206
|
+
}
|
|
3207
|
+
/**
|
|
3208
|
+
* Default iterator yielding `[key, value]` entries.
|
|
3209
|
+
* @returns Iterator of `[K, V]`.
|
|
3210
|
+
* @remarks Time O(n) to iterate, Space O(1)
|
|
3211
|
+
*/
|
|
3212
|
+
*[Symbol.iterator](...args) {
|
|
3213
|
+
yield* this._getIterator(...args);
|
|
3214
|
+
}
|
|
3215
|
+
/**
|
|
3216
|
+
* Iterate over `[key, value]` pairs (may yield `undefined` values).
|
|
3217
|
+
* @returns Iterator of `[K, V | undefined]`.
|
|
3218
|
+
* @remarks Time O(n), Space O(1)
|
|
3219
|
+
*/
|
|
3220
|
+
*entries() {
|
|
3221
|
+
for (const item of this) {
|
|
3222
|
+
yield item;
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
/**
|
|
3226
|
+
* Iterate over keys only.
|
|
3227
|
+
* @returns Iterator of keys.
|
|
3228
|
+
* @remarks Time O(n), Space O(1)
|
|
3229
|
+
*/
|
|
3230
|
+
*keys() {
|
|
3231
|
+
for (const item of this) {
|
|
3232
|
+
yield item[0];
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
/**
|
|
3236
|
+
* Iterate over values only.
|
|
3237
|
+
* @returns Iterator of values.
|
|
3238
|
+
* @remarks Time O(n), Space O(1)
|
|
3239
|
+
*/
|
|
3240
|
+
*values() {
|
|
3241
|
+
for (const item of this) {
|
|
3242
|
+
yield item[1];
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
/**
|
|
3246
|
+
* Test whether all entries satisfy the predicate.
|
|
3247
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
3248
|
+
* @param thisArg - Optional `this` for callback.
|
|
3249
|
+
* @returns `true` if all pass; otherwise `false`.
|
|
3250
|
+
* @remarks Time O(n), Space O(1)
|
|
3251
|
+
*/
|
|
3252
|
+
every(predicate, thisArg) {
|
|
3253
|
+
let index = 0;
|
|
3254
|
+
for (const item of this) {
|
|
3255
|
+
if (!predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
3256
|
+
return false;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
return true;
|
|
3260
|
+
}
|
|
3261
|
+
/**
|
|
3262
|
+
* Test whether any entry satisfies the predicate.
|
|
3263
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
3264
|
+
* @param thisArg - Optional `this` for callback.
|
|
3265
|
+
* @returns `true` if any passes; otherwise `false`.
|
|
3266
|
+
* @remarks Time O(n), Space O(1)
|
|
3267
|
+
*/
|
|
3268
|
+
some(predicate, thisArg) {
|
|
3269
|
+
let index = 0;
|
|
3270
|
+
for (const item of this) {
|
|
3271
|
+
if (predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
3272
|
+
return true;
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
return false;
|
|
3276
|
+
}
|
|
3277
|
+
/**
|
|
3278
|
+
* Visit each entry, left-to-right.
|
|
3279
|
+
* @param callbackfn - `(key, value, index, self) => void`.
|
|
3280
|
+
* @param thisArg - Optional `this` for callback.
|
|
3281
|
+
* @remarks Time O(n), Space O(1)
|
|
3282
|
+
*/
|
|
3283
|
+
forEach(callbackfn, thisArg) {
|
|
3284
|
+
let index = 0;
|
|
3285
|
+
for (const item of this) {
|
|
3286
|
+
const [key, value] = item;
|
|
3287
|
+
callbackfn.call(thisArg, value, key, index++, this);
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
/**
|
|
3291
|
+
* Find the first entry that matches a predicate.
|
|
3292
|
+
* @param callbackfn - `(key, value, index, self) => boolean`.
|
|
3293
|
+
* @param thisArg - Optional `this` for callback.
|
|
3294
|
+
* @returns Matching `[key, value]` or `undefined`.
|
|
3295
|
+
* @remarks Time O(n), Space O(1)
|
|
3296
|
+
*/
|
|
3297
|
+
find(callbackfn, thisArg) {
|
|
3298
|
+
let index = 0;
|
|
3299
|
+
for (const item of this) {
|
|
3300
|
+
const [key, value] = item;
|
|
3301
|
+
if (callbackfn.call(thisArg, value, key, index++, this)) return item;
|
|
3302
|
+
}
|
|
3303
|
+
return;
|
|
3304
|
+
}
|
|
3305
|
+
/**
|
|
3306
|
+
* Whether the given key exists.
|
|
3307
|
+
* @param key - Key to test.
|
|
3308
|
+
* @returns `true` if found; otherwise `false`.
|
|
3309
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
3310
|
+
*/
|
|
3311
|
+
has(key) {
|
|
3312
|
+
for (const item of this) {
|
|
3313
|
+
const [itemKey] = item;
|
|
3314
|
+
if (itemKey === key) return true;
|
|
3315
|
+
}
|
|
3316
|
+
return false;
|
|
3317
|
+
}
|
|
3318
|
+
/**
|
|
3319
|
+
* Whether there exists an entry with the given value.
|
|
3320
|
+
* @param value - Value to test.
|
|
3321
|
+
* @returns `true` if found; otherwise `false`.
|
|
3322
|
+
* @remarks Time O(n), Space O(1)
|
|
3323
|
+
*/
|
|
3324
|
+
hasValue(value) {
|
|
3325
|
+
for (const [, elementValue] of this) {
|
|
3326
|
+
if (elementValue === value) return true;
|
|
3327
|
+
}
|
|
3328
|
+
return false;
|
|
3329
|
+
}
|
|
3330
|
+
/**
|
|
3331
|
+
* Get the value under a key.
|
|
3332
|
+
* @param key - Key to look up.
|
|
3333
|
+
* @returns Value or `undefined`.
|
|
3334
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
3335
|
+
*/
|
|
3336
|
+
get(key) {
|
|
3337
|
+
for (const item of this) {
|
|
3338
|
+
const [itemKey, value] = item;
|
|
3339
|
+
if (itemKey === key) return value;
|
|
3340
|
+
}
|
|
3341
|
+
return;
|
|
3342
|
+
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Reduce entries into a single accumulator.
|
|
3345
|
+
* @param callbackfn - `(acc, value, key, index, self) => acc`.
|
|
3346
|
+
* @param initialValue - Initial accumulator.
|
|
3347
|
+
* @returns Final accumulator.
|
|
3348
|
+
* @remarks Time O(n), Space O(1)
|
|
3349
|
+
*/
|
|
3350
|
+
reduce(callbackfn, initialValue) {
|
|
3351
|
+
let accumulator = initialValue;
|
|
3352
|
+
let index = 0;
|
|
3353
|
+
for (const item of this) {
|
|
3354
|
+
const [key, value] = item;
|
|
3355
|
+
accumulator = callbackfn(accumulator, value, key, index++, this);
|
|
3356
|
+
}
|
|
3357
|
+
return accumulator;
|
|
3358
|
+
}
|
|
3359
|
+
/**
|
|
3360
|
+
* Converts data structure to `[key, value]` pairs.
|
|
3361
|
+
* @returns Array of entries.
|
|
3362
|
+
* @remarks Time O(n), Space O(n)
|
|
3363
|
+
*/
|
|
3364
|
+
toArray() {
|
|
3365
|
+
return [...this];
|
|
3366
|
+
}
|
|
3367
|
+
/**
|
|
3368
|
+
* Visualize the iterable as an array of `[key, value]` pairs (or a custom string).
|
|
3369
|
+
* @returns Array of entries (default) or a string.
|
|
3370
|
+
* @remarks Time O(n), Space O(n)
|
|
3371
|
+
*/
|
|
3372
|
+
toVisual() {
|
|
3373
|
+
return [...this];
|
|
3374
|
+
}
|
|
3375
|
+
/**
|
|
3376
|
+
* Print a human-friendly representation to the console.
|
|
3377
|
+
* @remarks Time O(n), Space O(n)
|
|
3378
|
+
*/
|
|
3379
|
+
print() {
|
|
3380
|
+
console.log(this.toVisual());
|
|
3381
|
+
}
|
|
3382
|
+
};
|
|
3383
|
+
|
|
1987
3384
|
// src/data-structures/linked-list/skip-linked-list.ts
|
|
1988
3385
|
var SkipListNode = class {
|
|
1989
3386
|
static {
|
|
@@ -1995,136 +3392,1033 @@ var SkipListNode = class {
|
|
|
1995
3392
|
constructor(key, value, level) {
|
|
1996
3393
|
this.key = key;
|
|
1997
3394
|
this.value = value;
|
|
1998
|
-
this.forward = new Array(level);
|
|
3395
|
+
this.forward = new Array(level).fill(void 0);
|
|
1999
3396
|
}
|
|
2000
3397
|
};
|
|
2001
|
-
var SkipList = class {
|
|
3398
|
+
var SkipList = class _SkipList extends IterableEntryBase {
|
|
2002
3399
|
static {
|
|
2003
3400
|
__name(this, "SkipList");
|
|
2004
3401
|
}
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
if (
|
|
2012
|
-
|
|
3402
|
+
#comparator;
|
|
3403
|
+
#isDefaultComparator;
|
|
3404
|
+
constructor(entries = [], options = {}) {
|
|
3405
|
+
super();
|
|
3406
|
+
const { comparator, toEntryFn, maxLevel, probability } = options;
|
|
3407
|
+
if (typeof maxLevel === "number" && maxLevel > 0) this._maxLevel = maxLevel;
|
|
3408
|
+
if (typeof probability === "number" && probability > 0 && probability < 1) this._probability = probability;
|
|
3409
|
+
this.#isDefaultComparator = comparator === void 0;
|
|
3410
|
+
this.#comparator = comparator ?? _SkipList.createDefaultComparator();
|
|
3411
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
3412
|
+
for (const item of entries) {
|
|
3413
|
+
let k;
|
|
3414
|
+
let v;
|
|
3415
|
+
if (toEntryFn) {
|
|
3416
|
+
[k, v] = toEntryFn(item);
|
|
3417
|
+
} else {
|
|
3418
|
+
if (!Array.isArray(item) || item.length < 2) {
|
|
3419
|
+
throw new TypeError(ERR.invalidEntry("SkipList"));
|
|
3420
|
+
}
|
|
3421
|
+
[k, v] = item;
|
|
3422
|
+
}
|
|
3423
|
+
this.set(k, v);
|
|
2013
3424
|
}
|
|
2014
3425
|
}
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
3426
|
+
/**
|
|
3427
|
+
* Creates a default comparator supporting number, string, Date, and bigint.
|
|
3428
|
+
*/
|
|
3429
|
+
static createDefaultComparator() {
|
|
3430
|
+
return (a, b) => {
|
|
3431
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
3432
|
+
if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("SkipList"));
|
|
3433
|
+
return a - b;
|
|
3434
|
+
}
|
|
3435
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
3436
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3437
|
+
}
|
|
3438
|
+
if (a instanceof Date && b instanceof Date) {
|
|
3439
|
+
const ta = a.getTime(), tb = b.getTime();
|
|
3440
|
+
if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("SkipList"));
|
|
3441
|
+
return ta - tb;
|
|
3442
|
+
}
|
|
3443
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
3444
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3445
|
+
}
|
|
3446
|
+
throw new TypeError(ERR.comparatorRequired("SkipList"));
|
|
3447
|
+
};
|
|
2018
3448
|
}
|
|
3449
|
+
// ─── Internal state ──────────────────────────────────────────
|
|
3450
|
+
_head;
|
|
2019
3451
|
_level = 0;
|
|
2020
|
-
|
|
2021
|
-
return this._level;
|
|
2022
|
-
}
|
|
3452
|
+
_size = 0;
|
|
2023
3453
|
_maxLevel = 16;
|
|
3454
|
+
_probability = 0.5;
|
|
3455
|
+
// ─── Size & lifecycle ────────────────────────────────────────
|
|
3456
|
+
get size() {
|
|
3457
|
+
return this._size;
|
|
3458
|
+
}
|
|
2024
3459
|
get maxLevel() {
|
|
2025
3460
|
return this._maxLevel;
|
|
2026
3461
|
}
|
|
2027
|
-
_probability = 0.5;
|
|
2028
3462
|
get probability() {
|
|
2029
3463
|
return this._probability;
|
|
2030
3464
|
}
|
|
2031
|
-
get
|
|
2032
|
-
|
|
2033
|
-
return firstNode ? firstNode.value : void 0;
|
|
3465
|
+
get comparator() {
|
|
3466
|
+
return this.#comparator;
|
|
2034
3467
|
}
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
3468
|
+
/**
|
|
3469
|
+
* Check if empty
|
|
3470
|
+
|
|
3471
|
+
|
|
3472
|
+
|
|
3473
|
+
|
|
3474
|
+
|
|
3475
|
+
|
|
3476
|
+
|
|
3477
|
+
|
|
3478
|
+
|
|
3479
|
+
|
|
3480
|
+
|
|
3481
|
+
|
|
3482
|
+
|
|
3483
|
+
|
|
3484
|
+
|
|
3485
|
+
|
|
3486
|
+
|
|
3487
|
+
|
|
3488
|
+
|
|
3489
|
+
|
|
3490
|
+
|
|
3491
|
+
|
|
3492
|
+
|
|
3493
|
+
|
|
3494
|
+
|
|
3495
|
+
|
|
3496
|
+
|
|
3497
|
+
|
|
3498
|
+
|
|
3499
|
+
* @example
|
|
3500
|
+
* // Check if empty
|
|
3501
|
+
* const sl = new SkipList<number, string>();
|
|
3502
|
+
* console.log(sl.isEmpty()); // true;
|
|
3503
|
+
*/
|
|
3504
|
+
isEmpty() {
|
|
3505
|
+
return this._size === 0;
|
|
2043
3506
|
}
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
3507
|
+
/**
|
|
3508
|
+
* Remove all entries
|
|
3509
|
+
|
|
3510
|
+
|
|
3511
|
+
|
|
3512
|
+
|
|
3513
|
+
|
|
3514
|
+
|
|
3515
|
+
|
|
3516
|
+
|
|
3517
|
+
|
|
3518
|
+
|
|
3519
|
+
|
|
3520
|
+
|
|
3521
|
+
|
|
3522
|
+
|
|
3523
|
+
|
|
3524
|
+
|
|
3525
|
+
|
|
3526
|
+
|
|
3527
|
+
|
|
3528
|
+
|
|
3529
|
+
|
|
3530
|
+
|
|
3531
|
+
|
|
3532
|
+
|
|
3533
|
+
|
|
3534
|
+
|
|
3535
|
+
|
|
3536
|
+
|
|
3537
|
+
|
|
3538
|
+
* @example
|
|
3539
|
+
* // Remove all entries
|
|
3540
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
3541
|
+
* sl.clear();
|
|
3542
|
+
* console.log(sl.isEmpty()); // true;
|
|
3543
|
+
*/
|
|
3544
|
+
clear() {
|
|
3545
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
3546
|
+
this._level = 0;
|
|
3547
|
+
this._size = 0;
|
|
3548
|
+
}
|
|
3549
|
+
/**
|
|
3550
|
+
* Create independent copy
|
|
3551
|
+
|
|
3552
|
+
|
|
3553
|
+
|
|
3554
|
+
|
|
3555
|
+
|
|
3556
|
+
|
|
3557
|
+
|
|
3558
|
+
|
|
3559
|
+
|
|
3560
|
+
|
|
3561
|
+
|
|
3562
|
+
|
|
3563
|
+
|
|
3564
|
+
|
|
3565
|
+
|
|
3566
|
+
|
|
3567
|
+
|
|
3568
|
+
|
|
3569
|
+
|
|
3570
|
+
|
|
3571
|
+
|
|
3572
|
+
|
|
3573
|
+
|
|
3574
|
+
|
|
3575
|
+
|
|
3576
|
+
|
|
3577
|
+
|
|
3578
|
+
|
|
3579
|
+
|
|
3580
|
+
* @example
|
|
3581
|
+
* // Create independent copy
|
|
3582
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
3583
|
+
* const copy = sl.clone();
|
|
3584
|
+
* copy.delete(1);
|
|
3585
|
+
* console.log(sl.has(1)); // true;
|
|
3586
|
+
*/
|
|
3587
|
+
clone() {
|
|
3588
|
+
return new _SkipList(this, {
|
|
3589
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
3590
|
+
maxLevel: this._maxLevel,
|
|
3591
|
+
probability: this._probability
|
|
3592
|
+
});
|
|
3593
|
+
}
|
|
3594
|
+
// ─── Core CRUD ───────────────────────────────────────────────
|
|
3595
|
+
/**
|
|
3596
|
+
* Insert or update a key-value pair. Returns `this` for chaining.
|
|
3597
|
+
* Unique keys only — if key exists, value is updated in place.
|
|
3598
|
+
|
|
3599
|
+
|
|
3600
|
+
|
|
3601
|
+
|
|
3602
|
+
|
|
3603
|
+
|
|
3604
|
+
|
|
3605
|
+
|
|
3606
|
+
|
|
3607
|
+
|
|
3608
|
+
|
|
3609
|
+
|
|
3610
|
+
|
|
3611
|
+
|
|
3612
|
+
|
|
3613
|
+
|
|
3614
|
+
|
|
3615
|
+
|
|
3616
|
+
|
|
3617
|
+
|
|
3618
|
+
|
|
3619
|
+
|
|
3620
|
+
|
|
3621
|
+
|
|
3622
|
+
|
|
3623
|
+
|
|
3624
|
+
|
|
3625
|
+
|
|
3626
|
+
|
|
3627
|
+
|
|
3628
|
+
|
|
3629
|
+
|
|
3630
|
+
* @example
|
|
3631
|
+
* // In-memory sorted key-value store
|
|
3632
|
+
* const store = new SkipList<number, string>();
|
|
3633
|
+
*
|
|
3634
|
+
* store.set(3, 'three');
|
|
3635
|
+
* store.set(1, 'one');
|
|
3636
|
+
* store.set(5, 'five');
|
|
3637
|
+
* store.set(2, 'two');
|
|
3638
|
+
*
|
|
3639
|
+
* console.log(store.get(3)); // 'three';
|
|
3640
|
+
* console.log(store.get(1)); // 'one';
|
|
3641
|
+
* console.log(store.get(5)); // 'five';
|
|
3642
|
+
*
|
|
3643
|
+
* // Update existing key
|
|
3644
|
+
* store.set(3, 'THREE');
|
|
3645
|
+
* console.log(store.get(3)); // 'THREE';
|
|
3646
|
+
*/
|
|
3647
|
+
set(key, value) {
|
|
3648
|
+
const cmp = this.#comparator;
|
|
3649
|
+
const update = this._findUpdate(key);
|
|
3650
|
+
const existing = update[0].forward[0];
|
|
3651
|
+
if (existing && cmp(existing.key, key) === 0) {
|
|
3652
|
+
existing.value = value;
|
|
3653
|
+
return this;
|
|
3654
|
+
}
|
|
3655
|
+
const newLevel = this._randomLevel();
|
|
3656
|
+
const newNode = new SkipListNode(key, value, newLevel);
|
|
3657
|
+
if (newLevel > this._level) {
|
|
3658
|
+
for (let i = this._level; i < newLevel; i++) {
|
|
3659
|
+
update[i] = this._head;
|
|
2051
3660
|
}
|
|
2052
|
-
|
|
3661
|
+
this._level = newLevel;
|
|
2053
3662
|
}
|
|
2054
|
-
for (let i = 0; i <
|
|
3663
|
+
for (let i = 0; i < newLevel; i++) {
|
|
2055
3664
|
newNode.forward[i] = update[i].forward[i];
|
|
2056
3665
|
update[i].forward[i] = newNode;
|
|
2057
3666
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
}
|
|
3667
|
+
this._size++;
|
|
3668
|
+
return this;
|
|
2061
3669
|
}
|
|
3670
|
+
/**
|
|
3671
|
+
* Get the value for a key, or `undefined` if not found.
|
|
3672
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
3673
|
+
|
|
3674
|
+
|
|
3675
|
+
|
|
3676
|
+
|
|
3677
|
+
|
|
3678
|
+
|
|
3679
|
+
|
|
3680
|
+
|
|
3681
|
+
|
|
3682
|
+
|
|
3683
|
+
|
|
3684
|
+
|
|
3685
|
+
|
|
3686
|
+
|
|
3687
|
+
|
|
3688
|
+
|
|
3689
|
+
|
|
3690
|
+
|
|
3691
|
+
|
|
3692
|
+
|
|
3693
|
+
|
|
3694
|
+
|
|
3695
|
+
|
|
3696
|
+
|
|
3697
|
+
|
|
3698
|
+
|
|
3699
|
+
|
|
3700
|
+
|
|
3701
|
+
|
|
3702
|
+
|
|
3703
|
+
|
|
3704
|
+
|
|
3705
|
+
* @example
|
|
3706
|
+
* // Building a sorted index
|
|
3707
|
+
* type Product = { id: number; name: string; price: number };
|
|
3708
|
+
* const products: Product[] = [
|
|
3709
|
+
* { id: 1, name: 'Widget', price: 25 },
|
|
3710
|
+
* { id: 2, name: 'Gadget', price: 50 },
|
|
3711
|
+
* { id: 3, name: 'Doohickey', price: 15 }
|
|
3712
|
+
* ];
|
|
3713
|
+
*
|
|
3714
|
+
* const index = new SkipList<number, Product, Product>(products, {
|
|
3715
|
+
* toEntryFn: (p: Product) => [p.price, p]
|
|
3716
|
+
* });
|
|
3717
|
+
*
|
|
3718
|
+
* // Iterate in sorted order by price
|
|
3719
|
+
* const names = [...index.values()].map(p => p!.name);
|
|
3720
|
+
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
3721
|
+
*
|
|
3722
|
+
* // Range search: products between $20 and $60
|
|
3723
|
+
* const range = index.rangeSearch([20, 60]);
|
|
3724
|
+
* console.log(range.map(([, p]) => p!.name)); // ['Widget', 'Gadget'];
|
|
3725
|
+
*/
|
|
2062
3726
|
get(key) {
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
while (current.forward[i] && current.forward[i].key < key) {
|
|
2066
|
-
current = current.forward[i];
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
current = current.forward[0];
|
|
2070
|
-
if (current && current.key === key) {
|
|
2071
|
-
return current.value;
|
|
2072
|
-
}
|
|
2073
|
-
return void 0;
|
|
3727
|
+
const node = this._findNode(key);
|
|
3728
|
+
return node ? node.value : void 0;
|
|
2074
3729
|
}
|
|
3730
|
+
/**
|
|
3731
|
+
* Check if a key exists.
|
|
3732
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
3733
|
+
|
|
3734
|
+
|
|
3735
|
+
|
|
3736
|
+
|
|
3737
|
+
|
|
3738
|
+
|
|
3739
|
+
|
|
3740
|
+
|
|
3741
|
+
|
|
3742
|
+
|
|
3743
|
+
|
|
3744
|
+
|
|
3745
|
+
|
|
3746
|
+
|
|
3747
|
+
|
|
3748
|
+
|
|
3749
|
+
|
|
3750
|
+
|
|
3751
|
+
|
|
3752
|
+
|
|
3753
|
+
|
|
3754
|
+
|
|
3755
|
+
|
|
3756
|
+
|
|
3757
|
+
|
|
3758
|
+
|
|
3759
|
+
|
|
3760
|
+
|
|
3761
|
+
|
|
3762
|
+
|
|
3763
|
+
|
|
3764
|
+
|
|
3765
|
+
* @example
|
|
3766
|
+
* // Check key existence
|
|
3767
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [3, 'c'], [5, 'e']]);
|
|
3768
|
+
* console.log(sl.has(3)); // true;
|
|
3769
|
+
* console.log(sl.has(4)); // false;
|
|
3770
|
+
*/
|
|
2075
3771
|
has(key) {
|
|
2076
|
-
return this.
|
|
3772
|
+
return this._findNode(key) !== void 0;
|
|
2077
3773
|
}
|
|
3774
|
+
/**
|
|
3775
|
+
* Delete a key. Returns `true` if the key was found and removed.
|
|
3776
|
+
|
|
3777
|
+
|
|
3778
|
+
|
|
3779
|
+
|
|
3780
|
+
|
|
3781
|
+
|
|
3782
|
+
|
|
3783
|
+
|
|
3784
|
+
|
|
3785
|
+
|
|
3786
|
+
|
|
3787
|
+
|
|
3788
|
+
|
|
3789
|
+
|
|
3790
|
+
|
|
3791
|
+
|
|
3792
|
+
|
|
3793
|
+
|
|
3794
|
+
|
|
3795
|
+
|
|
3796
|
+
|
|
3797
|
+
|
|
3798
|
+
|
|
3799
|
+
|
|
3800
|
+
|
|
3801
|
+
|
|
3802
|
+
|
|
3803
|
+
|
|
3804
|
+
|
|
3805
|
+
|
|
3806
|
+
|
|
3807
|
+
|
|
3808
|
+
* @example
|
|
3809
|
+
* // Fast lookup with deletion
|
|
3810
|
+
* const cache = new SkipList<string, number>();
|
|
3811
|
+
*
|
|
3812
|
+
* cache.set('alpha', 1);
|
|
3813
|
+
* cache.set('beta', 2);
|
|
3814
|
+
* cache.set('gamma', 3);
|
|
3815
|
+
*
|
|
3816
|
+
* console.log(cache.has('beta')); // true;
|
|
3817
|
+
* cache.delete('beta');
|
|
3818
|
+
* console.log(cache.has('beta')); // false;
|
|
3819
|
+
* console.log(cache.size); // 2;
|
|
3820
|
+
*/
|
|
2078
3821
|
delete(key) {
|
|
2079
|
-
const
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
3822
|
+
const cmp = this.#comparator;
|
|
3823
|
+
const update = this._findUpdate(key);
|
|
3824
|
+
const target = update[0].forward[0];
|
|
3825
|
+
if (!target || cmp(target.key, key) !== 0) return false;
|
|
3826
|
+
for (let i = 0; i < this._level; i++) {
|
|
3827
|
+
if (update[i].forward[i] !== target) break;
|
|
3828
|
+
update[i].forward[i] = target.forward[i];
|
|
3829
|
+
}
|
|
3830
|
+
while (this._level > 0 && !this._head.forward[this._level - 1]) {
|
|
3831
|
+
this._level--;
|
|
3832
|
+
}
|
|
3833
|
+
this._size--;
|
|
3834
|
+
return true;
|
|
3835
|
+
}
|
|
3836
|
+
// ─── Navigation ──────────────────────────────────────────────
|
|
3837
|
+
/**
|
|
3838
|
+
* Returns the first (smallest key) entry, or `undefined` if empty.
|
|
3839
|
+
|
|
3840
|
+
|
|
3841
|
+
|
|
3842
|
+
|
|
3843
|
+
|
|
3844
|
+
|
|
3845
|
+
|
|
3846
|
+
|
|
3847
|
+
|
|
3848
|
+
|
|
3849
|
+
|
|
3850
|
+
|
|
3851
|
+
|
|
3852
|
+
|
|
3853
|
+
|
|
3854
|
+
|
|
3855
|
+
|
|
3856
|
+
|
|
3857
|
+
|
|
3858
|
+
|
|
3859
|
+
|
|
3860
|
+
|
|
3861
|
+
|
|
3862
|
+
|
|
3863
|
+
|
|
3864
|
+
|
|
3865
|
+
|
|
3866
|
+
|
|
3867
|
+
|
|
3868
|
+
|
|
3869
|
+
|
|
3870
|
+
|
|
3871
|
+
* @example
|
|
3872
|
+
* // Access the minimum entry
|
|
3873
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3874
|
+
* console.log(sl.first()); // [1, 'a'];
|
|
3875
|
+
*/
|
|
3876
|
+
first() {
|
|
3877
|
+
const node = this._head.forward[0];
|
|
3878
|
+
return node ? [node.key, node.value] : void 0;
|
|
3879
|
+
}
|
|
3880
|
+
/**
|
|
3881
|
+
* Returns the last (largest key) entry, or `undefined` if empty.
|
|
3882
|
+
|
|
3883
|
+
|
|
3884
|
+
|
|
3885
|
+
|
|
3886
|
+
|
|
3887
|
+
|
|
3888
|
+
|
|
3889
|
+
|
|
3890
|
+
|
|
3891
|
+
|
|
3892
|
+
|
|
3893
|
+
|
|
3894
|
+
|
|
3895
|
+
|
|
3896
|
+
|
|
3897
|
+
|
|
3898
|
+
|
|
3899
|
+
|
|
3900
|
+
|
|
3901
|
+
|
|
3902
|
+
|
|
3903
|
+
|
|
3904
|
+
|
|
3905
|
+
|
|
3906
|
+
|
|
3907
|
+
|
|
3908
|
+
|
|
3909
|
+
|
|
3910
|
+
|
|
3911
|
+
|
|
3912
|
+
|
|
3913
|
+
|
|
3914
|
+
* @example
|
|
3915
|
+
* // Access the maximum entry
|
|
3916
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3917
|
+
* console.log(sl.last()); // [5, 'e'];
|
|
3918
|
+
*/
|
|
3919
|
+
last() {
|
|
3920
|
+
let current = this._head;
|
|
3921
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3922
|
+
while (current.forward[i]) {
|
|
2083
3923
|
current = current.forward[i];
|
|
2084
3924
|
}
|
|
2085
|
-
update[i] = current;
|
|
2086
3925
|
}
|
|
2087
|
-
current
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
3926
|
+
return current === this._head ? void 0 : [current.key, current.value];
|
|
3927
|
+
}
|
|
3928
|
+
/**
|
|
3929
|
+
* Remove and return the first (smallest key) entry.
|
|
3930
|
+
|
|
3931
|
+
|
|
3932
|
+
|
|
3933
|
+
|
|
3934
|
+
|
|
3935
|
+
|
|
3936
|
+
|
|
3937
|
+
|
|
3938
|
+
|
|
3939
|
+
|
|
3940
|
+
|
|
3941
|
+
|
|
3942
|
+
|
|
3943
|
+
|
|
3944
|
+
|
|
3945
|
+
|
|
3946
|
+
|
|
3947
|
+
|
|
3948
|
+
|
|
3949
|
+
|
|
3950
|
+
|
|
3951
|
+
|
|
3952
|
+
|
|
3953
|
+
|
|
3954
|
+
|
|
3955
|
+
|
|
3956
|
+
|
|
3957
|
+
|
|
3958
|
+
|
|
3959
|
+
* @example
|
|
3960
|
+
* // Remove and return smallest
|
|
3961
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
3962
|
+
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
3963
|
+
* console.log(sl.size); // 2;
|
|
3964
|
+
*/
|
|
3965
|
+
pollFirst() {
|
|
3966
|
+
const entry = this.first();
|
|
3967
|
+
if (!entry) return void 0;
|
|
3968
|
+
this.delete(entry[0]);
|
|
3969
|
+
return entry;
|
|
3970
|
+
}
|
|
3971
|
+
/**
|
|
3972
|
+
* Remove and return the last (largest key) entry.
|
|
3973
|
+
|
|
3974
|
+
|
|
3975
|
+
|
|
3976
|
+
|
|
3977
|
+
|
|
3978
|
+
|
|
3979
|
+
|
|
3980
|
+
|
|
3981
|
+
|
|
3982
|
+
|
|
3983
|
+
|
|
3984
|
+
|
|
3985
|
+
|
|
3986
|
+
|
|
3987
|
+
|
|
3988
|
+
|
|
3989
|
+
|
|
3990
|
+
|
|
3991
|
+
|
|
3992
|
+
|
|
3993
|
+
|
|
3994
|
+
|
|
3995
|
+
|
|
3996
|
+
|
|
3997
|
+
|
|
3998
|
+
|
|
3999
|
+
|
|
4000
|
+
|
|
4001
|
+
|
|
4002
|
+
* @example
|
|
4003
|
+
* // Remove and return largest
|
|
4004
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
4005
|
+
* console.log(sl.pollLast()); // [3, 'c'];
|
|
4006
|
+
* console.log(sl.size); // 2;
|
|
4007
|
+
*/
|
|
4008
|
+
pollLast() {
|
|
4009
|
+
const entry = this.last();
|
|
4010
|
+
if (!entry) return void 0;
|
|
4011
|
+
this.delete(entry[0]);
|
|
4012
|
+
return entry;
|
|
4013
|
+
}
|
|
4014
|
+
/**
|
|
4015
|
+
* Least entry ≥ key, or `undefined`.
|
|
4016
|
+
|
|
4017
|
+
|
|
4018
|
+
|
|
4019
|
+
|
|
4020
|
+
|
|
4021
|
+
|
|
4022
|
+
|
|
4023
|
+
|
|
4024
|
+
|
|
4025
|
+
|
|
4026
|
+
|
|
4027
|
+
|
|
4028
|
+
|
|
4029
|
+
|
|
4030
|
+
|
|
4031
|
+
|
|
4032
|
+
|
|
4033
|
+
|
|
4034
|
+
|
|
4035
|
+
|
|
4036
|
+
|
|
4037
|
+
|
|
4038
|
+
|
|
4039
|
+
|
|
4040
|
+
|
|
4041
|
+
|
|
4042
|
+
|
|
4043
|
+
|
|
4044
|
+
|
|
4045
|
+
|
|
4046
|
+
|
|
4047
|
+
|
|
4048
|
+
* @example
|
|
4049
|
+
* // Least entry ≥ key
|
|
4050
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4051
|
+
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
4052
|
+
* console.log(sl.ceiling(20)); // [20, 'b'];
|
|
4053
|
+
*/
|
|
4054
|
+
ceiling(key) {
|
|
4055
|
+
const cmp = this.#comparator;
|
|
4056
|
+
let current = this._head;
|
|
4057
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4058
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4059
|
+
current = current.forward[i];
|
|
2094
4060
|
}
|
|
2095
|
-
|
|
2096
|
-
|
|
4061
|
+
}
|
|
4062
|
+
const node = current.forward[0];
|
|
4063
|
+
return node ? [node.key, node.value] : void 0;
|
|
4064
|
+
}
|
|
4065
|
+
/**
|
|
4066
|
+
* Greatest entry ≤ key, or `undefined`.
|
|
4067
|
+
|
|
4068
|
+
|
|
4069
|
+
|
|
4070
|
+
|
|
4071
|
+
|
|
4072
|
+
|
|
4073
|
+
|
|
4074
|
+
|
|
4075
|
+
|
|
4076
|
+
|
|
4077
|
+
|
|
4078
|
+
|
|
4079
|
+
|
|
4080
|
+
|
|
4081
|
+
|
|
4082
|
+
|
|
4083
|
+
|
|
4084
|
+
|
|
4085
|
+
|
|
4086
|
+
|
|
4087
|
+
|
|
4088
|
+
|
|
4089
|
+
|
|
4090
|
+
|
|
4091
|
+
|
|
4092
|
+
|
|
4093
|
+
|
|
4094
|
+
|
|
4095
|
+
|
|
4096
|
+
|
|
4097
|
+
|
|
4098
|
+
|
|
4099
|
+
* @example
|
|
4100
|
+
* // Greatest entry ≤ key
|
|
4101
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4102
|
+
* console.log(sl.floor(25)); // [20, 'b'];
|
|
4103
|
+
* console.log(sl.floor(5)); // undefined;
|
|
4104
|
+
*/
|
|
4105
|
+
floor(key) {
|
|
4106
|
+
const cmp = this.#comparator;
|
|
4107
|
+
let current = this._head;
|
|
4108
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4109
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
4110
|
+
current = current.forward[i];
|
|
2097
4111
|
}
|
|
2098
|
-
return true;
|
|
2099
4112
|
}
|
|
2100
|
-
|
|
4113
|
+
const result = current === this._head ? void 0 : current;
|
|
4114
|
+
if (result && cmp(result.key, key) <= 0) return [result.key, result.value];
|
|
4115
|
+
return void 0;
|
|
2101
4116
|
}
|
|
4117
|
+
/**
|
|
4118
|
+
* Least entry strictly > key, or `undefined`.
|
|
4119
|
+
|
|
4120
|
+
|
|
4121
|
+
|
|
4122
|
+
|
|
4123
|
+
|
|
4124
|
+
|
|
4125
|
+
|
|
4126
|
+
|
|
4127
|
+
|
|
4128
|
+
|
|
4129
|
+
|
|
4130
|
+
|
|
4131
|
+
|
|
4132
|
+
|
|
4133
|
+
|
|
4134
|
+
|
|
4135
|
+
|
|
4136
|
+
|
|
4137
|
+
|
|
4138
|
+
|
|
4139
|
+
|
|
4140
|
+
|
|
4141
|
+
|
|
4142
|
+
|
|
4143
|
+
|
|
4144
|
+
|
|
4145
|
+
|
|
4146
|
+
|
|
4147
|
+
|
|
4148
|
+
* @example
|
|
4149
|
+
* // Strictly greater entry
|
|
4150
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4151
|
+
* console.log(sl.higher(15)); // [20, 'b'];
|
|
4152
|
+
* console.log(sl.higher(30)); // undefined;
|
|
4153
|
+
*/
|
|
2102
4154
|
higher(key) {
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
4155
|
+
const cmp = this.#comparator;
|
|
4156
|
+
let current = this._head;
|
|
4157
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4158
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
2106
4159
|
current = current.forward[i];
|
|
2107
4160
|
}
|
|
2108
4161
|
}
|
|
2109
|
-
const
|
|
2110
|
-
return
|
|
4162
|
+
const node = current.forward[0];
|
|
4163
|
+
return node ? [node.key, node.value] : void 0;
|
|
2111
4164
|
}
|
|
4165
|
+
/**
|
|
4166
|
+
* Greatest entry strictly < key, or `undefined`.
|
|
4167
|
+
|
|
4168
|
+
|
|
4169
|
+
|
|
4170
|
+
|
|
4171
|
+
|
|
4172
|
+
|
|
4173
|
+
|
|
4174
|
+
|
|
4175
|
+
|
|
4176
|
+
|
|
4177
|
+
|
|
4178
|
+
|
|
4179
|
+
|
|
4180
|
+
|
|
4181
|
+
|
|
4182
|
+
|
|
4183
|
+
|
|
4184
|
+
|
|
4185
|
+
|
|
4186
|
+
|
|
4187
|
+
|
|
4188
|
+
|
|
4189
|
+
|
|
4190
|
+
|
|
4191
|
+
|
|
4192
|
+
|
|
4193
|
+
|
|
4194
|
+
|
|
4195
|
+
|
|
4196
|
+
* @example
|
|
4197
|
+
* // Strictly less entry
|
|
4198
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4199
|
+
* console.log(sl.lower(25)); // [20, 'b'];
|
|
4200
|
+
* console.log(sl.lower(10)); // undefined;
|
|
4201
|
+
*/
|
|
2112
4202
|
lower(key) {
|
|
2113
|
-
|
|
2114
|
-
let
|
|
2115
|
-
|
|
2116
|
-
|
|
4203
|
+
const cmp = this.#comparator;
|
|
4204
|
+
let current = this._head;
|
|
4205
|
+
let result;
|
|
4206
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4207
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4208
|
+
current = current.forward[i];
|
|
4209
|
+
}
|
|
4210
|
+
if (current !== this._head && cmp(current.key, key) < 0) {
|
|
4211
|
+
result = current;
|
|
4212
|
+
}
|
|
4213
|
+
}
|
|
4214
|
+
return result ? [result.key, result.value] : void 0;
|
|
4215
|
+
}
|
|
4216
|
+
/**
|
|
4217
|
+
* Returns entries within the given key range.
|
|
4218
|
+
|
|
4219
|
+
|
|
4220
|
+
|
|
4221
|
+
|
|
4222
|
+
|
|
4223
|
+
|
|
4224
|
+
|
|
4225
|
+
|
|
4226
|
+
|
|
4227
|
+
|
|
4228
|
+
|
|
4229
|
+
|
|
4230
|
+
|
|
4231
|
+
|
|
4232
|
+
|
|
4233
|
+
|
|
4234
|
+
|
|
4235
|
+
|
|
4236
|
+
|
|
4237
|
+
|
|
4238
|
+
|
|
4239
|
+
|
|
4240
|
+
|
|
4241
|
+
|
|
4242
|
+
|
|
4243
|
+
|
|
4244
|
+
|
|
4245
|
+
|
|
4246
|
+
|
|
4247
|
+
|
|
4248
|
+
|
|
4249
|
+
|
|
4250
|
+
* @example
|
|
4251
|
+
* // Find entries in a range
|
|
4252
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]);
|
|
4253
|
+
* const result = sl.rangeSearch([2, 4]);
|
|
4254
|
+
* console.log(result); // [[2, 'b'], [3, 'c'], [4, 'd']];
|
|
4255
|
+
*/
|
|
4256
|
+
rangeSearch(range, options = {}) {
|
|
4257
|
+
const { lowInclusive = true, highInclusive = true } = options;
|
|
4258
|
+
const [low, high] = range;
|
|
4259
|
+
const cmp = this.#comparator;
|
|
4260
|
+
const out = [];
|
|
4261
|
+
let current = this._head;
|
|
4262
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4263
|
+
while (current.forward[i] && cmp(current.forward[i].key, low) < 0) {
|
|
4264
|
+
current = current.forward[i];
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
current = current.forward[0];
|
|
4268
|
+
while (current) {
|
|
4269
|
+
const cmpHigh = cmp(current.key, high);
|
|
4270
|
+
if (cmpHigh > 0) break;
|
|
4271
|
+
if (cmpHigh === 0 && !highInclusive) break;
|
|
4272
|
+
const cmpLow = cmp(current.key, low);
|
|
4273
|
+
if (cmpLow > 0 || cmpLow === 0 && lowInclusive) {
|
|
4274
|
+
out.push([current.key, current.value]);
|
|
4275
|
+
}
|
|
4276
|
+
current = current.forward[0];
|
|
4277
|
+
}
|
|
4278
|
+
return out;
|
|
4279
|
+
}
|
|
4280
|
+
// ─── Functional (overrides) ──────────────────────────────────
|
|
4281
|
+
/**
|
|
4282
|
+
* Creates a new SkipList with entries transformed by callback.
|
|
4283
|
+
|
|
4284
|
+
|
|
4285
|
+
|
|
4286
|
+
|
|
4287
|
+
|
|
4288
|
+
|
|
4289
|
+
|
|
4290
|
+
|
|
4291
|
+
|
|
4292
|
+
|
|
4293
|
+
|
|
4294
|
+
|
|
4295
|
+
|
|
4296
|
+
|
|
4297
|
+
|
|
4298
|
+
|
|
4299
|
+
|
|
4300
|
+
|
|
4301
|
+
|
|
4302
|
+
|
|
4303
|
+
|
|
4304
|
+
|
|
4305
|
+
|
|
4306
|
+
|
|
4307
|
+
|
|
4308
|
+
|
|
4309
|
+
|
|
4310
|
+
|
|
4311
|
+
|
|
4312
|
+
* @example
|
|
4313
|
+
* // Transform entries
|
|
4314
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
4315
|
+
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
4316
|
+
* console.log([...mapped.values()]); // ['A', 'B'];
|
|
4317
|
+
*/
|
|
4318
|
+
map(callback, options) {
|
|
4319
|
+
const out = new _SkipList([], options ?? {});
|
|
4320
|
+
let i = 0;
|
|
4321
|
+
for (const [k, v] of this) {
|
|
4322
|
+
const [nk, nv] = callback(v, k, i++, this);
|
|
4323
|
+
out.set(nk, nv);
|
|
4324
|
+
}
|
|
4325
|
+
return out;
|
|
4326
|
+
}
|
|
4327
|
+
/**
|
|
4328
|
+
* Creates a new SkipList with entries that pass the predicate.
|
|
4329
|
+
|
|
4330
|
+
|
|
4331
|
+
|
|
4332
|
+
|
|
4333
|
+
|
|
4334
|
+
|
|
4335
|
+
|
|
4336
|
+
|
|
4337
|
+
|
|
4338
|
+
|
|
4339
|
+
|
|
4340
|
+
|
|
4341
|
+
|
|
4342
|
+
|
|
4343
|
+
|
|
4344
|
+
|
|
4345
|
+
|
|
4346
|
+
|
|
4347
|
+
|
|
4348
|
+
|
|
4349
|
+
|
|
4350
|
+
|
|
4351
|
+
|
|
4352
|
+
|
|
4353
|
+
|
|
4354
|
+
|
|
4355
|
+
|
|
4356
|
+
|
|
4357
|
+
|
|
4358
|
+
* @example
|
|
4359
|
+
* // Filter entries
|
|
4360
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
4361
|
+
* const result = sl.filter((v, k) => k > 1);
|
|
4362
|
+
* console.log(result.size); // 2;
|
|
4363
|
+
*/
|
|
4364
|
+
filter(callbackfn, thisArg) {
|
|
4365
|
+
const out = new _SkipList([], {
|
|
4366
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
4367
|
+
maxLevel: this._maxLevel,
|
|
4368
|
+
probability: this._probability
|
|
4369
|
+
});
|
|
4370
|
+
let i = 0;
|
|
4371
|
+
for (const [k, v] of this) {
|
|
4372
|
+
const ok = callbackfn.call(thisArg, v, k, i++, this);
|
|
4373
|
+
if (ok) out.set(k, v);
|
|
4374
|
+
}
|
|
4375
|
+
return out;
|
|
4376
|
+
}
|
|
4377
|
+
// ─── Iterator (required by IterableEntryBase) ────────────────
|
|
4378
|
+
_getIterator() {
|
|
4379
|
+
const head = this._head;
|
|
4380
|
+
return (function* () {
|
|
4381
|
+
let node = head.forward[0];
|
|
4382
|
+
while (node) {
|
|
4383
|
+
yield [node.key, node.value];
|
|
4384
|
+
node = node.forward[0];
|
|
4385
|
+
}
|
|
4386
|
+
})();
|
|
4387
|
+
}
|
|
4388
|
+
// ─── Internal helpers ────────────────────────────────────────
|
|
4389
|
+
/**
|
|
4390
|
+
* Finds the update array (predecessors at each level) for a given key.
|
|
4391
|
+
*/
|
|
4392
|
+
_findUpdate(key) {
|
|
4393
|
+
const cmp = this.#comparator;
|
|
4394
|
+
const update = new Array(this._maxLevel).fill(this._head);
|
|
4395
|
+
let current = this._head;
|
|
4396
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4397
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
2117
4398
|
current = current.forward[i];
|
|
2118
4399
|
}
|
|
2119
|
-
|
|
2120
|
-
|
|
4400
|
+
update[i] = current;
|
|
4401
|
+
}
|
|
4402
|
+
return update;
|
|
4403
|
+
}
|
|
4404
|
+
/**
|
|
4405
|
+
* Finds the node for a given key, or undefined.
|
|
4406
|
+
*/
|
|
4407
|
+
_findNode(key) {
|
|
4408
|
+
const cmp = this.#comparator;
|
|
4409
|
+
let current = this._head;
|
|
4410
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4411
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4412
|
+
current = current.forward[i];
|
|
2121
4413
|
}
|
|
2122
4414
|
}
|
|
2123
|
-
|
|
4415
|
+
const candidate = current.forward[0];
|
|
4416
|
+
if (candidate && cmp(candidate.key, key) === 0) return candidate;
|
|
4417
|
+
return void 0;
|
|
2124
4418
|
}
|
|
2125
4419
|
_randomLevel() {
|
|
2126
4420
|
let level = 1;
|
|
2127
|
-
while (Math.random() < this.
|
|
4421
|
+
while (Math.random() < this._probability && level < this._maxLevel) {
|
|
2128
4422
|
level++;
|
|
2129
4423
|
}
|
|
2130
4424
|
return level;
|