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/cjs/index.cjs
CHANGED
|
@@ -3,55 +3,6 @@
|
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
5
5
|
|
|
6
|
-
// src/common/error.ts
|
|
7
|
-
var ERR = {
|
|
8
|
-
// Range / index
|
|
9
|
-
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
|
|
10
|
-
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
|
|
11
|
-
// Type / argument
|
|
12
|
-
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
|
|
13
|
-
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
|
|
14
|
-
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
|
|
15
|
-
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
|
|
16
|
-
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
|
|
17
|
-
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
|
|
18
|
-
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
|
|
19
|
-
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
|
|
20
|
-
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
|
|
21
|
-
// State / operation
|
|
22
|
-
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
|
|
23
|
-
// Matrix
|
|
24
|
-
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
|
|
25
|
-
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
|
|
26
|
-
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
|
|
27
|
-
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
|
|
28
|
-
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
// src/common/index.ts
|
|
32
|
-
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
33
|
-
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
34
|
-
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
35
|
-
return DFSOperation2;
|
|
36
|
-
})(DFSOperation || {});
|
|
37
|
-
var Range = class {
|
|
38
|
-
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
39
|
-
this.low = low;
|
|
40
|
-
this.high = high;
|
|
41
|
-
this.includeLow = includeLow;
|
|
42
|
-
this.includeHigh = includeHigh;
|
|
43
|
-
}
|
|
44
|
-
static {
|
|
45
|
-
__name(this, "Range");
|
|
46
|
-
}
|
|
47
|
-
// Determine whether a key is within the range
|
|
48
|
-
isInRange(key, comparator) {
|
|
49
|
-
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
50
|
-
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
51
|
-
return lowCheck && highCheck;
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
|
|
55
6
|
// src/data-structures/base/iterable-element-base.ts
|
|
56
7
|
var IterableElementBase = class {
|
|
57
8
|
static {
|
|
@@ -70,7 +21,7 @@ var IterableElementBase = class {
|
|
|
70
21
|
if (options) {
|
|
71
22
|
const { toElementFn } = options;
|
|
72
23
|
if (typeof toElementFn === "function") this._toElementFn = toElementFn;
|
|
73
|
-
else if (toElementFn) throw new TypeError(
|
|
24
|
+
else if (toElementFn) throw new TypeError("toElementFn must be a function type");
|
|
74
25
|
}
|
|
75
26
|
}
|
|
76
27
|
/**
|
|
@@ -233,7 +184,7 @@ var IterableElementBase = class {
|
|
|
233
184
|
acc = initialValue;
|
|
234
185
|
} else {
|
|
235
186
|
const first = iter.next();
|
|
236
|
-
if (first.done) throw new TypeError(
|
|
187
|
+
if (first.done) throw new TypeError("Reduce of empty structure with no initial value");
|
|
237
188
|
acc = first.value;
|
|
238
189
|
index = 1;
|
|
239
190
|
}
|
|
@@ -774,11 +725,58 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
774
725
|
return list;
|
|
775
726
|
}
|
|
776
727
|
/**
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
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
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
* @example
|
|
765
|
+
* // basic SinglyLinkedList creation and push operation
|
|
766
|
+
* // Create a simple SinglyLinkedList with initial values
|
|
767
|
+
* const list = new SinglyLinkedList([1, 2, 3, 4, 5]);
|
|
768
|
+
*
|
|
769
|
+
* // Verify the list maintains insertion order
|
|
770
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
771
|
+
*
|
|
772
|
+
* // Check length
|
|
773
|
+
* console.log(list.length); // 5;
|
|
774
|
+
*
|
|
775
|
+
* // Push a new element to the end
|
|
776
|
+
* list.push(6);
|
|
777
|
+
* console.log(list.length); // 6;
|
|
778
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
779
|
+
*/
|
|
782
780
|
push(elementOrNode) {
|
|
783
781
|
const newNode = this._ensureNode(elementOrNode);
|
|
784
782
|
if (!this.head) {
|
|
@@ -792,10 +790,57 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
792
790
|
return true;
|
|
793
791
|
}
|
|
794
792
|
/**
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
793
|
+
* Remove and return the tail element.
|
|
794
|
+
* @remarks Time O(N), Space O(1)
|
|
795
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
827
|
+
|
|
828
|
+
* @example
|
|
829
|
+
* // SinglyLinkedList pop and shift operations
|
|
830
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
831
|
+
*
|
|
832
|
+
* // Pop removes from the end
|
|
833
|
+
* const last = list.pop();
|
|
834
|
+
* console.log(last); // 50;
|
|
835
|
+
*
|
|
836
|
+
* // Shift removes from the beginning
|
|
837
|
+
* const first = list.shift();
|
|
838
|
+
* console.log(first); // 10;
|
|
839
|
+
*
|
|
840
|
+
* // Verify remaining elements
|
|
841
|
+
* console.log([...list]); // [20, 30, 40];
|
|
842
|
+
* console.log(list.length); // 3;
|
|
843
|
+
*/
|
|
799
844
|
pop() {
|
|
800
845
|
if (!this.head) return void 0;
|
|
801
846
|
if (this.head === this.tail) {
|
|
@@ -814,10 +859,47 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
814
859
|
return value;
|
|
815
860
|
}
|
|
816
861
|
/**
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
862
|
+
* Remove and return the head element.
|
|
863
|
+
* @remarks Time O(1), Space O(1)
|
|
864
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
896
|
+
|
|
897
|
+
* @example
|
|
898
|
+
* // Remove from the front
|
|
899
|
+
* const list = new SinglyLinkedList<number>([10, 20, 30]);
|
|
900
|
+
* console.log(list.shift()); // 10;
|
|
901
|
+
* console.log(list.length); // 2;
|
|
902
|
+
*/
|
|
821
903
|
shift() {
|
|
822
904
|
if (!this.head) return void 0;
|
|
823
905
|
const removed = this.head;
|
|
@@ -827,11 +909,63 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
827
909
|
return removed.value;
|
|
828
910
|
}
|
|
829
911
|
/**
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
912
|
+
* Prepend an element/node to the head.
|
|
913
|
+
* @remarks Time O(1), Space O(1)
|
|
914
|
+
* @param elementOrNode - Element or node to prepend.
|
|
915
|
+
* @returns True when prepended.
|
|
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
|
+
|
|
947
|
+
|
|
948
|
+
* @example
|
|
949
|
+
* // SinglyLinkedList unshift and forward traversal
|
|
950
|
+
* const list = new SinglyLinkedList<number>([20, 30, 40]);
|
|
951
|
+
*
|
|
952
|
+
* // Unshift adds to the beginning
|
|
953
|
+
* list.unshift(10);
|
|
954
|
+
* console.log([...list]); // [10, 20, 30, 40];
|
|
955
|
+
*
|
|
956
|
+
* // Access elements (forward traversal only for singly linked)
|
|
957
|
+
* const second = list.at(1);
|
|
958
|
+
* console.log(second); // 20;
|
|
959
|
+
*
|
|
960
|
+
* // SinglyLinkedList allows forward iteration only
|
|
961
|
+
* const elements: number[] = [];
|
|
962
|
+
* for (const item of list) {
|
|
963
|
+
* elements.push(item);
|
|
964
|
+
* }
|
|
965
|
+
* console.log(elements); // [10, 20, 30, 40];
|
|
966
|
+
*
|
|
967
|
+
* console.log(list.length); // 4;
|
|
968
|
+
*/
|
|
835
969
|
unshift(elementOrNode) {
|
|
836
970
|
const newNode = this._ensureNode(elementOrNode);
|
|
837
971
|
if (!this.head) {
|
|
@@ -887,11 +1021,49 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
887
1021
|
return void 0;
|
|
888
1022
|
}
|
|
889
1023
|
/**
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1024
|
+
* Get the element at a given index.
|
|
1025
|
+
* @remarks Time O(N), Space O(1)
|
|
1026
|
+
* @param index - Zero-based index.
|
|
1027
|
+
* @returns Element or undefined.
|
|
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
|
+
|
|
1059
|
+
|
|
1060
|
+
* @example
|
|
1061
|
+
* // Access element by index
|
|
1062
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c', 'd']);
|
|
1063
|
+
* console.log(list.at(0)); // 'a';
|
|
1064
|
+
* console.log(list.at(2)); // 'c';
|
|
1065
|
+
* console.log(list.at(3)); // 'd';
|
|
1066
|
+
*/
|
|
895
1067
|
at(index) {
|
|
896
1068
|
if (index < 0 || index >= this._length) return void 0;
|
|
897
1069
|
let current = this.head;
|
|
@@ -908,11 +1080,44 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
908
1080
|
return elementNodeOrPredicate instanceof SinglyLinkedListNode;
|
|
909
1081
|
}
|
|
910
1082
|
/**
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1083
|
+
* Get the node reference at a given index.
|
|
1084
|
+
* @remarks Time O(N), Space O(1)
|
|
1085
|
+
* @param index - Zero-based index.
|
|
1086
|
+
* @returns Node or undefined.
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
* @example
|
|
1117
|
+
* // Get node at index
|
|
1118
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
1119
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
1120
|
+
*/
|
|
916
1121
|
getNodeAt(index) {
|
|
917
1122
|
if (index < 0 || index >= this._length) return void 0;
|
|
918
1123
|
let current = this.head;
|
|
@@ -920,11 +1125,45 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
920
1125
|
return current;
|
|
921
1126
|
}
|
|
922
1127
|
/**
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1128
|
+
* Delete the element at an index.
|
|
1129
|
+
* @remarks Time O(N), Space O(1)
|
|
1130
|
+
* @param index - Zero-based index.
|
|
1131
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
1160
|
+
|
|
1161
|
+
* @example
|
|
1162
|
+
* // Remove by index
|
|
1163
|
+
* const list = new SinglyLinkedList<string>(['a', 'b', 'c']);
|
|
1164
|
+
* list.deleteAt(1);
|
|
1165
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
1166
|
+
*/
|
|
928
1167
|
deleteAt(index) {
|
|
929
1168
|
if (index < 0 || index >= this._length) return void 0;
|
|
930
1169
|
if (index === 0) return this.shift();
|
|
@@ -937,11 +1176,45 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
937
1176
|
return value;
|
|
938
1177
|
}
|
|
939
1178
|
/**
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1179
|
+
* Delete the first match by value/node.
|
|
1180
|
+
* @remarks Time O(N), Space O(1)
|
|
1181
|
+
* @param [elementOrNode] - Element or node to remove; if omitted/undefined, nothing happens.
|
|
1182
|
+
* @returns True if removed.
|
|
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
|
+
|
|
1211
|
+
|
|
1212
|
+
* @example
|
|
1213
|
+
* // Remove first occurrence
|
|
1214
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 2]);
|
|
1215
|
+
* list.delete(2);
|
|
1216
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
1217
|
+
*/
|
|
945
1218
|
delete(elementOrNode) {
|
|
946
1219
|
if (elementOrNode === void 0 || !this.head) return false;
|
|
947
1220
|
const node = this.isNode(elementOrNode) ? elementOrNode : this.getNode(elementOrNode);
|
|
@@ -958,12 +1231,46 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
958
1231
|
return true;
|
|
959
1232
|
}
|
|
960
1233
|
/**
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
1234
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
1235
|
+
* @remarks Time O(N), Space O(1)
|
|
1236
|
+
* @param index - Zero-based index.
|
|
1237
|
+
* @param newElementOrNode - Element or node to insert.
|
|
1238
|
+
* @returns True if inserted.
|
|
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
|
+
|
|
1267
|
+
|
|
1268
|
+
* @example
|
|
1269
|
+
* // Insert at index
|
|
1270
|
+
* const list = new SinglyLinkedList<number>([1, 3]);
|
|
1271
|
+
* list.addAt(1, 2);
|
|
1272
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
1273
|
+
*/
|
|
967
1274
|
addAt(index, newElementOrNode) {
|
|
968
1275
|
if (index < 0 || index > this._length) return false;
|
|
969
1276
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -989,28 +1296,133 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
989
1296
|
return true;
|
|
990
1297
|
}
|
|
991
1298
|
/**
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1299
|
+
* Check whether the list is empty.
|
|
1300
|
+
* @remarks Time O(1), Space O(1)
|
|
1301
|
+
* @returns True if length is 0.
|
|
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
|
+
|
|
1331
|
+
|
|
1332
|
+
* @example
|
|
1333
|
+
* // Check empty
|
|
1334
|
+
* console.log(new SinglyLinkedList().isEmpty()); // true;
|
|
1335
|
+
*/
|
|
996
1336
|
isEmpty() {
|
|
997
1337
|
return this._length === 0;
|
|
998
1338
|
}
|
|
999
1339
|
/**
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1340
|
+
* Remove all nodes and reset length.
|
|
1341
|
+
* @remarks Time O(N), Space O(1)
|
|
1342
|
+
* @returns void
|
|
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
|
+
|
|
1372
|
+
|
|
1373
|
+
* @example
|
|
1374
|
+
* // Remove all
|
|
1375
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1376
|
+
* list.clear();
|
|
1377
|
+
* console.log(list.isEmpty()); // true;
|
|
1378
|
+
*/
|
|
1004
1379
|
clear() {
|
|
1005
1380
|
this._head = void 0;
|
|
1006
1381
|
this._tail = void 0;
|
|
1007
1382
|
this._length = 0;
|
|
1008
1383
|
}
|
|
1009
1384
|
/**
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1385
|
+
* Reverse the list in place.
|
|
1386
|
+
* @remarks Time O(N), Space O(1)
|
|
1387
|
+
* @returns This list.
|
|
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
|
+
|
|
1419
|
+
|
|
1420
|
+
* @example
|
|
1421
|
+
* // Reverse the list in-place
|
|
1422
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4]);
|
|
1423
|
+
* list.reverse();
|
|
1424
|
+
* console.log([...list]); // [4, 3, 2, 1];
|
|
1425
|
+
*/
|
|
1014
1426
|
reverse() {
|
|
1015
1427
|
if (!this.head || this.head === this.tail) return this;
|
|
1016
1428
|
let prev;
|
|
@@ -1185,22 +1597,106 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1185
1597
|
return false;
|
|
1186
1598
|
}
|
|
1187
1599
|
/**
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1600
|
+
* Deep clone this list (values are copied by reference).
|
|
1601
|
+
* @remarks Time O(N), Space O(N)
|
|
1602
|
+
* @returns A new list with the same element sequence.
|
|
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
|
+
|
|
1632
|
+
|
|
1633
|
+
* @example
|
|
1634
|
+
* // Deep copy
|
|
1635
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1636
|
+
* const copy = list.clone();
|
|
1637
|
+
* copy.pop();
|
|
1638
|
+
* console.log(list.length); // 3;
|
|
1639
|
+
* console.log(copy.length); // 2;
|
|
1640
|
+
*/
|
|
1192
1641
|
clone() {
|
|
1193
1642
|
const out = this._createInstance();
|
|
1194
1643
|
for (const v of this) out.push(v);
|
|
1195
1644
|
return out;
|
|
1196
1645
|
}
|
|
1197
1646
|
/**
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1647
|
+
* Filter values into a new list of the same class.
|
|
1648
|
+
* @remarks Time O(N), Space O(N)
|
|
1649
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
1650
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1651
|
+
* @returns A new list with kept values.
|
|
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
|
+
|
|
1683
|
+
|
|
1684
|
+
* @example
|
|
1685
|
+
* // SinglyLinkedList filter and map operations
|
|
1686
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
1687
|
+
*
|
|
1688
|
+
* // Filter even numbers
|
|
1689
|
+
* const filtered = list.filter(value => value % 2 === 0);
|
|
1690
|
+
* console.log(filtered.length); // 2;
|
|
1691
|
+
*
|
|
1692
|
+
* // Map to double values
|
|
1693
|
+
* const doubled = list.map(value => value * 2);
|
|
1694
|
+
* console.log(doubled.length); // 5;
|
|
1695
|
+
*
|
|
1696
|
+
* // Use reduce to sum
|
|
1697
|
+
* const sum = list.reduce((acc, value) => acc + value, 0);
|
|
1698
|
+
* console.log(sum); // 15;
|
|
1699
|
+
*/
|
|
1204
1700
|
filter(callback, thisArg) {
|
|
1205
1701
|
const out = this._createInstance();
|
|
1206
1702
|
let index = 0;
|
|
@@ -1224,15 +1720,52 @@ var SinglyLinkedList = class extends LinearLinkedBase {
|
|
|
1224
1720
|
return out;
|
|
1225
1721
|
}
|
|
1226
1722
|
/**
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1723
|
+
* Map values into a new list (possibly different element type).
|
|
1724
|
+
* @remarks Time O(N), Space O(N)
|
|
1725
|
+
* @template EM
|
|
1726
|
+
* @template RM
|
|
1727
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
1728
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
1729
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
1730
|
+
* @returns A new SinglyLinkedList with mapped values.
|
|
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
|
+
|
|
1762
|
+
|
|
1763
|
+
* @example
|
|
1764
|
+
* // Transform elements
|
|
1765
|
+
* const list = new SinglyLinkedList<number>([1, 2, 3]);
|
|
1766
|
+
* const doubled = list.map(n => n * 2);
|
|
1767
|
+
* console.log([...doubled]); // [2, 4, 6];
|
|
1768
|
+
*/
|
|
1236
1769
|
map(callback, options, thisArg) {
|
|
1237
1770
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1238
1771
|
let index = 0;
|
|
@@ -1508,11 +2041,58 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1508
2041
|
return elementNodeOrPredicate instanceof DoublyLinkedListNode;
|
|
1509
2042
|
}
|
|
1510
2043
|
/**
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
2044
|
+
* Append an element/node to the tail.
|
|
2045
|
+
* @remarks Time O(1), Space O(1)
|
|
2046
|
+
* @param elementOrNode - Element or node to append.
|
|
2047
|
+
* @returns True when appended.
|
|
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
|
+
|
|
2079
|
+
|
|
2080
|
+
* @example
|
|
2081
|
+
* // basic DoublyLinkedList creation and push operation
|
|
2082
|
+
* // Create a simple DoublyLinkedList with initial values
|
|
2083
|
+
* const list = new DoublyLinkedList([1, 2, 3, 4, 5]);
|
|
2084
|
+
*
|
|
2085
|
+
* // Verify the list maintains insertion order
|
|
2086
|
+
* console.log([...list]); // [1, 2, 3, 4, 5];
|
|
2087
|
+
*
|
|
2088
|
+
* // Check length
|
|
2089
|
+
* console.log(list.length); // 5;
|
|
2090
|
+
*
|
|
2091
|
+
* // Push a new element to the end
|
|
2092
|
+
* list.push(6);
|
|
2093
|
+
* console.log(list.length); // 6;
|
|
2094
|
+
* console.log([...list]); // [1, 2, 3, 4, 5, 6];
|
|
2095
|
+
*/
|
|
1516
2096
|
push(elementOrNode) {
|
|
1517
2097
|
const newNode = this._ensureNode(elementOrNode);
|
|
1518
2098
|
if (!this.head) {
|
|
@@ -1528,10 +2108,57 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1528
2108
|
return true;
|
|
1529
2109
|
}
|
|
1530
2110
|
/**
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
2111
|
+
* Remove and return the tail element.
|
|
2112
|
+
* @remarks Time O(1), Space O(1)
|
|
2113
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
2145
|
+
|
|
2146
|
+
* @example
|
|
2147
|
+
* // DoublyLinkedList pop and shift operations
|
|
2148
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30, 40, 50]);
|
|
2149
|
+
*
|
|
2150
|
+
* // Pop removes from the end
|
|
2151
|
+
* const last = list.pop();
|
|
2152
|
+
* console.log(last); // 50;
|
|
2153
|
+
*
|
|
2154
|
+
* // Shift removes from the beginning
|
|
2155
|
+
* const first = list.shift();
|
|
2156
|
+
* console.log(first); // 10;
|
|
2157
|
+
*
|
|
2158
|
+
* // Verify remaining elements
|
|
2159
|
+
* console.log([...list]); // [20, 30, 40];
|
|
2160
|
+
* console.log(list.length); // 3;
|
|
2161
|
+
*/
|
|
1535
2162
|
pop() {
|
|
1536
2163
|
if (!this.tail) return void 0;
|
|
1537
2164
|
const removed = this.tail;
|
|
@@ -1546,10 +2173,47 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1546
2173
|
return removed.value;
|
|
1547
2174
|
}
|
|
1548
2175
|
/**
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
2176
|
+
* Remove and return the head element.
|
|
2177
|
+
* @remarks Time O(1), Space O(1)
|
|
2178
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
2210
|
+
|
|
2211
|
+
* @example
|
|
2212
|
+
* // Remove from the front
|
|
2213
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
2214
|
+
* console.log(list.shift()); // 10;
|
|
2215
|
+
* console.log(list.first); // 20;
|
|
2216
|
+
*/
|
|
1553
2217
|
shift() {
|
|
1554
2218
|
if (!this.head) return void 0;
|
|
1555
2219
|
const removed = this.head;
|
|
@@ -1564,11 +2228,48 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1564
2228
|
return removed.value;
|
|
1565
2229
|
}
|
|
1566
2230
|
/**
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
2231
|
+
* Prepend an element/node to the head.
|
|
2232
|
+
* @remarks Time O(1), Space O(1)
|
|
2233
|
+
* @param elementOrNode - Element or node to prepend.
|
|
2234
|
+
* @returns True when prepended.
|
|
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
|
+
|
|
2266
|
+
|
|
2267
|
+
* @example
|
|
2268
|
+
* // Add to the front
|
|
2269
|
+
* const list = new DoublyLinkedList<number>([2, 3]);
|
|
2270
|
+
* list.unshift(1);
|
|
2271
|
+
* console.log([...list]); // [1, 2, 3];
|
|
2272
|
+
*/
|
|
1572
2273
|
unshift(elementOrNode) {
|
|
1573
2274
|
const newNode = this._ensureNode(elementOrNode);
|
|
1574
2275
|
if (!this.head) {
|
|
@@ -1612,11 +2313,48 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1612
2313
|
return ans;
|
|
1613
2314
|
}
|
|
1614
2315
|
/**
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
2316
|
+
* Get the element at a given index.
|
|
2317
|
+
* @remarks Time O(N), Space O(1)
|
|
2318
|
+
* @param index - Zero-based index.
|
|
2319
|
+
* @returns Element or undefined.
|
|
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
|
+
|
|
2351
|
+
|
|
2352
|
+
* @example
|
|
2353
|
+
* // Access by index
|
|
2354
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2355
|
+
* console.log(list.at(1)); // 'b';
|
|
2356
|
+
* console.log(list.at(2)); // 'c';
|
|
2357
|
+
*/
|
|
1620
2358
|
at(index) {
|
|
1621
2359
|
if (index < 0 || index >= this._length) return void 0;
|
|
1622
2360
|
let current = this.head;
|
|
@@ -1624,11 +2362,44 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1624
2362
|
return current?.value;
|
|
1625
2363
|
}
|
|
1626
2364
|
/**
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
2365
|
+
* Get the node reference at a given index.
|
|
2366
|
+
* @remarks Time O(N), Space O(1)
|
|
2367
|
+
* @param index - Zero-based index.
|
|
2368
|
+
* @returns Node or undefined.
|
|
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
|
+
|
|
2397
|
+
|
|
2398
|
+
* @example
|
|
2399
|
+
* // Get node at index
|
|
2400
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2401
|
+
* console.log(list.getNodeAt(1)?.value); // 'b';
|
|
2402
|
+
*/
|
|
1632
2403
|
getNodeAt(index) {
|
|
1633
2404
|
if (index < 0 || index >= this._length) return void 0;
|
|
1634
2405
|
let current = this.head;
|
|
@@ -1667,12 +2438,46 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1667
2438
|
return void 0;
|
|
1668
2439
|
}
|
|
1669
2440
|
/**
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
2441
|
+
* Insert a new element/node at an index, shifting following nodes.
|
|
2442
|
+
* @remarks Time O(N), Space O(1)
|
|
2443
|
+
* @param index - Zero-based index.
|
|
2444
|
+
* @param newElementOrNode - Element or node to insert.
|
|
2445
|
+
* @returns True if inserted.
|
|
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
|
+
|
|
2474
|
+
|
|
2475
|
+
* @example
|
|
2476
|
+
* // Insert at position
|
|
2477
|
+
* const list = new DoublyLinkedList<number>([1, 3]);
|
|
2478
|
+
* list.addAt(1, 2);
|
|
2479
|
+
* console.log(list.toArray()); // [1, 2, 3];
|
|
2480
|
+
*/
|
|
1676
2481
|
addAt(index, newElementOrNode) {
|
|
1677
2482
|
if (index < 0 || index > this._length) return false;
|
|
1678
2483
|
if (index === 0) return this.unshift(newElementOrNode);
|
|
@@ -1739,11 +2544,45 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1739
2544
|
return true;
|
|
1740
2545
|
}
|
|
1741
2546
|
/**
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
2547
|
+
* Delete the element at an index.
|
|
2548
|
+
* @remarks Time O(N), Space O(1)
|
|
2549
|
+
* @param index - Zero-based index.
|
|
2550
|
+
* @returns Removed element or undefined.
|
|
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
|
+
|
|
2579
|
+
|
|
2580
|
+
* @example
|
|
2581
|
+
* // Remove by index
|
|
2582
|
+
* const list = new DoublyLinkedList<string>(['a', 'b', 'c']);
|
|
2583
|
+
* list.deleteAt(1);
|
|
2584
|
+
* console.log(list.toArray()); // ['a', 'c'];
|
|
2585
|
+
*/
|
|
1747
2586
|
deleteAt(index) {
|
|
1748
2587
|
if (index < 0 || index >= this._length) return;
|
|
1749
2588
|
if (index === 0) return this.shift();
|
|
@@ -1757,11 +2596,45 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1757
2596
|
return removedNode.value;
|
|
1758
2597
|
}
|
|
1759
2598
|
/**
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
2599
|
+
* Delete the first match by value/node.
|
|
2600
|
+
* @remarks Time O(N), Space O(1)
|
|
2601
|
+
* @param [elementOrNode] - Element or node to remove.
|
|
2602
|
+
* @returns True if removed.
|
|
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
|
+
|
|
2631
|
+
|
|
2632
|
+
* @example
|
|
2633
|
+
* // Remove first occurrence
|
|
2634
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 2]);
|
|
2635
|
+
* list.delete(2);
|
|
2636
|
+
* console.log(list.toArray()); // [1, 3, 2];
|
|
2637
|
+
*/
|
|
1765
2638
|
delete(elementOrNode) {
|
|
1766
2639
|
const node = this.getNode(elementOrNode);
|
|
1767
2640
|
if (!node) return false;
|
|
@@ -1777,29 +2650,131 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1777
2650
|
return true;
|
|
1778
2651
|
}
|
|
1779
2652
|
/**
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
2653
|
+
* Check whether the list is empty.
|
|
2654
|
+
* @remarks Time O(1), Space O(1)
|
|
2655
|
+
* @returns True if length is 0.
|
|
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
|
+
|
|
2685
|
+
|
|
2686
|
+
* @example
|
|
2687
|
+
* // Check empty
|
|
2688
|
+
* console.log(new DoublyLinkedList().isEmpty()); // true;
|
|
2689
|
+
*/
|
|
1784
2690
|
isEmpty() {
|
|
1785
2691
|
return this._length === 0;
|
|
1786
2692
|
}
|
|
1787
2693
|
/**
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
2694
|
+
* Remove all nodes and reset length.
|
|
2695
|
+
* @remarks Time O(N), Space O(1)
|
|
2696
|
+
* @returns void
|
|
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
|
+
|
|
2726
|
+
|
|
2727
|
+
* @example
|
|
2728
|
+
* // Remove all
|
|
2729
|
+
* const list = new DoublyLinkedList<number>([1, 2]);
|
|
2730
|
+
* list.clear();
|
|
2731
|
+
* console.log(list.isEmpty()); // true;
|
|
2732
|
+
*/
|
|
1792
2733
|
clear() {
|
|
1793
2734
|
this._head = void 0;
|
|
1794
2735
|
this._tail = void 0;
|
|
1795
2736
|
this._length = 0;
|
|
1796
2737
|
}
|
|
1797
2738
|
/**
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
2739
|
+
* Find the first value matching a predicate scanning forward.
|
|
2740
|
+
* @remarks Time O(N), Space O(1)
|
|
2741
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2742
|
+
* @returns Matched value or undefined.
|
|
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
|
+
|
|
2771
|
+
|
|
2772
|
+
* @example
|
|
2773
|
+
* // Search with predicate
|
|
2774
|
+
* const list = new DoublyLinkedList<number>([10, 20, 30]);
|
|
2775
|
+
* const found = list.search(node => node.value > 15);
|
|
2776
|
+
* console.log(found); // 20;
|
|
2777
|
+
*/
|
|
1803
2778
|
search(elementNodeOrPredicate) {
|
|
1804
2779
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1805
2780
|
let current = this.head;
|
|
@@ -1810,11 +2785,46 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1810
2785
|
return void 0;
|
|
1811
2786
|
}
|
|
1812
2787
|
/**
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2788
|
+
* Find the first value matching a predicate scanning backward.
|
|
2789
|
+
* @remarks Time O(N), Space O(1)
|
|
2790
|
+
* @param elementNodeOrPredicate - Element, node, or predicate to match.
|
|
2791
|
+
* @returns Matched value or undefined.
|
|
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
|
+
|
|
2820
|
+
|
|
2821
|
+
* @example
|
|
2822
|
+
* // Find value scanning from tail
|
|
2823
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4]);
|
|
2824
|
+
* // getBackward scans from tail to head, returns first match
|
|
2825
|
+
* const found = list.getBackward(node => node.value < 4);
|
|
2826
|
+
* console.log(found); // 3;
|
|
2827
|
+
*/
|
|
1818
2828
|
getBackward(elementNodeOrPredicate) {
|
|
1819
2829
|
const predicate = this._ensurePredicate(elementNodeOrPredicate);
|
|
1820
2830
|
let current = this.tail;
|
|
@@ -1825,10 +2835,47 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1825
2835
|
return void 0;
|
|
1826
2836
|
}
|
|
1827
2837
|
/**
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
2838
|
+
* Reverse the list in place.
|
|
2839
|
+
* @remarks Time O(N), Space O(1)
|
|
2840
|
+
* @returns This list.
|
|
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
|
+
|
|
2872
|
+
|
|
2873
|
+
* @example
|
|
2874
|
+
* // Reverse in-place
|
|
2875
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2876
|
+
* list.reverse();
|
|
2877
|
+
* console.log([...list]); // [3, 2, 1];
|
|
2878
|
+
*/
|
|
1832
2879
|
reverse() {
|
|
1833
2880
|
let current = this.head;
|
|
1834
2881
|
[this._head, this._tail] = [this.tail, this.head];
|
|
@@ -1850,22 +2897,95 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1850
2897
|
return this;
|
|
1851
2898
|
}
|
|
1852
2899
|
/**
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
2900
|
+
* Deep clone this list (values are copied by reference).
|
|
2901
|
+
* @remarks Time O(N), Space O(N)
|
|
2902
|
+
* @returns A new list with the same element sequence.
|
|
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
|
+
|
|
2932
|
+
|
|
2933
|
+
* @example
|
|
2934
|
+
* // Deep copy
|
|
2935
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3]);
|
|
2936
|
+
* const copy = list.clone();
|
|
2937
|
+
* copy.pop();
|
|
2938
|
+
* console.log(list.length); // 3;
|
|
2939
|
+
*/
|
|
1857
2940
|
clone() {
|
|
1858
2941
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1859
2942
|
for (const v of this) out.push(v);
|
|
1860
2943
|
return out;
|
|
1861
2944
|
}
|
|
1862
2945
|
/**
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
2946
|
+
* Filter values into a new list of the same class.
|
|
2947
|
+
* @remarks Time O(N), Space O(N)
|
|
2948
|
+
* @param callback - Predicate (value, index, list) → boolean to keep value.
|
|
2949
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
2950
|
+
* @returns A new list with kept values.
|
|
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
|
+
|
|
2982
|
+
|
|
2983
|
+
* @example
|
|
2984
|
+
* // Filter elements
|
|
2985
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
2986
|
+
* const evens = list.filter(n => n % 2 === 0);
|
|
2987
|
+
* console.log([...evens]); // [2, 4];
|
|
2988
|
+
*/
|
|
1869
2989
|
filter(callback, thisArg) {
|
|
1870
2990
|
const out = this._createInstance({ toElementFn: this._toElementFn, maxLen: this._maxLen });
|
|
1871
2991
|
let index = 0;
|
|
@@ -1889,15 +3009,61 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1889
3009
|
return out;
|
|
1890
3010
|
}
|
|
1891
3011
|
/**
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
3012
|
+
* Map values into a new list (possibly different element type).
|
|
3013
|
+
* @remarks Time O(N), Space O(N)
|
|
3014
|
+
* @template EM
|
|
3015
|
+
* @template RM
|
|
3016
|
+
* @param callback - Mapping function (value, index, list) → newElement.
|
|
3017
|
+
* @param [options] - Options for the output list (e.g., maxLen, toElementFn).
|
|
3018
|
+
* @param [thisArg] - Value for `this` inside the callback.
|
|
3019
|
+
* @returns A new DoublyLinkedList with mapped values.
|
|
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
|
+
|
|
3051
|
+
|
|
3052
|
+
* @example
|
|
3053
|
+
* // DoublyLinkedList for...of iteration and map operation
|
|
3054
|
+
* const list = new DoublyLinkedList<number>([1, 2, 3, 4, 5]);
|
|
3055
|
+
*
|
|
3056
|
+
* // Iterate through list
|
|
3057
|
+
* const doubled = list.map(value => value * 2);
|
|
3058
|
+
* console.log(doubled.length); // 5;
|
|
3059
|
+
*
|
|
3060
|
+
* // Use for...of loop
|
|
3061
|
+
* const result: number[] = [];
|
|
3062
|
+
* for (const item of list) {
|
|
3063
|
+
* result.push(item);
|
|
3064
|
+
* }
|
|
3065
|
+
* console.log(result); // [1, 2, 3, 4, 5];
|
|
3066
|
+
*/
|
|
1901
3067
|
map(callback, options, thisArg) {
|
|
1902
3068
|
const out = this._createLike([], { ...options ?? {}, maxLen: this._maxLen });
|
|
1903
3069
|
let index = 0;
|
|
@@ -1986,6 +3152,237 @@ var DoublyLinkedList = class extends LinearLinkedBase {
|
|
|
1986
3152
|
}
|
|
1987
3153
|
};
|
|
1988
3154
|
|
|
3155
|
+
// src/common/error.ts
|
|
3156
|
+
var ERR = {
|
|
3157
|
+
// Range / index
|
|
3158
|
+
indexOutOfRange: /* @__PURE__ */ __name((index, min, max, ctx) => `${ctx ? ctx + ": " : ""}Index ${index} is out of range [${min}, ${max}].`, "indexOutOfRange"),
|
|
3159
|
+
invalidIndex: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Index must be an integer.`, "invalidIndex"),
|
|
3160
|
+
// Type / argument
|
|
3161
|
+
invalidArgument: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidArgument"),
|
|
3162
|
+
comparatorRequired: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Comparator is required for non-number/non-string/non-Date keys.`, "comparatorRequired"),
|
|
3163
|
+
invalidKey: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidKey"),
|
|
3164
|
+
notAFunction: /* @__PURE__ */ __name((name, ctx) => `${ctx ? ctx + ": " : ""}${name} must be a function.`, "notAFunction"),
|
|
3165
|
+
invalidEntry: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Each entry must be a [key, value] tuple.`, "invalidEntry"),
|
|
3166
|
+
invalidNaN: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}NaN is not a valid key.`, "invalidNaN"),
|
|
3167
|
+
invalidDate: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Invalid Date key.`, "invalidDate"),
|
|
3168
|
+
reduceEmpty: /* @__PURE__ */ __name((ctx) => `${ctx ? ctx + ": " : ""}Reduce of empty structure with no initial value.`, "reduceEmpty"),
|
|
3169
|
+
callbackReturnType: /* @__PURE__ */ __name((expected, got, ctx) => `${ctx ? ctx + ": " : ""}Callback must return ${expected}; got ${got}.`, "callbackReturnType"),
|
|
3170
|
+
// State / operation
|
|
3171
|
+
invalidOperation: /* @__PURE__ */ __name((reason, ctx) => `${ctx ? ctx + ": " : ""}${reason}`, "invalidOperation"),
|
|
3172
|
+
// Matrix
|
|
3173
|
+
matrixDimensionMismatch: /* @__PURE__ */ __name((op) => `Matrix: Dimensions must be compatible for ${op}.`, "matrixDimensionMismatch"),
|
|
3174
|
+
matrixSingular: /* @__PURE__ */ __name(() => "Matrix: Singular matrix, inverse does not exist.", "matrixSingular"),
|
|
3175
|
+
matrixNotSquare: /* @__PURE__ */ __name(() => "Matrix: Must be square for inversion.", "matrixNotSquare"),
|
|
3176
|
+
matrixNotRectangular: /* @__PURE__ */ __name(() => "Matrix: Must be rectangular for transposition.", "matrixNotRectangular"),
|
|
3177
|
+
matrixRowMismatch: /* @__PURE__ */ __name((expected, got) => `Matrix: Expected row length ${expected}, but got ${got}.`, "matrixRowMismatch")
|
|
3178
|
+
};
|
|
3179
|
+
|
|
3180
|
+
// src/common/index.ts
|
|
3181
|
+
var DFSOperation = /* @__PURE__ */ ((DFSOperation2) => {
|
|
3182
|
+
DFSOperation2[DFSOperation2["VISIT"] = 0] = "VISIT";
|
|
3183
|
+
DFSOperation2[DFSOperation2["PROCESS"] = 1] = "PROCESS";
|
|
3184
|
+
return DFSOperation2;
|
|
3185
|
+
})(DFSOperation || {});
|
|
3186
|
+
var Range = class {
|
|
3187
|
+
constructor(low, high, includeLow = true, includeHigh = true) {
|
|
3188
|
+
this.low = low;
|
|
3189
|
+
this.high = high;
|
|
3190
|
+
this.includeLow = includeLow;
|
|
3191
|
+
this.includeHigh = includeHigh;
|
|
3192
|
+
}
|
|
3193
|
+
static {
|
|
3194
|
+
__name(this, "Range");
|
|
3195
|
+
}
|
|
3196
|
+
// Determine whether a key is within the range
|
|
3197
|
+
isInRange(key, comparator) {
|
|
3198
|
+
const lowCheck = this.includeLow ? comparator(key, this.low) >= 0 : comparator(key, this.low) > 0;
|
|
3199
|
+
const highCheck = this.includeHigh ? comparator(key, this.high) <= 0 : comparator(key, this.high) < 0;
|
|
3200
|
+
return lowCheck && highCheck;
|
|
3201
|
+
}
|
|
3202
|
+
};
|
|
3203
|
+
|
|
3204
|
+
// src/data-structures/base/iterable-entry-base.ts
|
|
3205
|
+
var IterableEntryBase = class {
|
|
3206
|
+
static {
|
|
3207
|
+
__name(this, "IterableEntryBase");
|
|
3208
|
+
}
|
|
3209
|
+
/**
|
|
3210
|
+
* Default iterator yielding `[key, value]` entries.
|
|
3211
|
+
* @returns Iterator of `[K, V]`.
|
|
3212
|
+
* @remarks Time O(n) to iterate, Space O(1)
|
|
3213
|
+
*/
|
|
3214
|
+
*[Symbol.iterator](...args) {
|
|
3215
|
+
yield* this._getIterator(...args);
|
|
3216
|
+
}
|
|
3217
|
+
/**
|
|
3218
|
+
* Iterate over `[key, value]` pairs (may yield `undefined` values).
|
|
3219
|
+
* @returns Iterator of `[K, V | undefined]`.
|
|
3220
|
+
* @remarks Time O(n), Space O(1)
|
|
3221
|
+
*/
|
|
3222
|
+
*entries() {
|
|
3223
|
+
for (const item of this) {
|
|
3224
|
+
yield item;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* Iterate over keys only.
|
|
3229
|
+
* @returns Iterator of keys.
|
|
3230
|
+
* @remarks Time O(n), Space O(1)
|
|
3231
|
+
*/
|
|
3232
|
+
*keys() {
|
|
3233
|
+
for (const item of this) {
|
|
3234
|
+
yield item[0];
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
/**
|
|
3238
|
+
* Iterate over values only.
|
|
3239
|
+
* @returns Iterator of values.
|
|
3240
|
+
* @remarks Time O(n), Space O(1)
|
|
3241
|
+
*/
|
|
3242
|
+
*values() {
|
|
3243
|
+
for (const item of this) {
|
|
3244
|
+
yield item[1];
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
/**
|
|
3248
|
+
* Test whether all entries satisfy the predicate.
|
|
3249
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
3250
|
+
* @param thisArg - Optional `this` for callback.
|
|
3251
|
+
* @returns `true` if all pass; otherwise `false`.
|
|
3252
|
+
* @remarks Time O(n), Space O(1)
|
|
3253
|
+
*/
|
|
3254
|
+
every(predicate, thisArg) {
|
|
3255
|
+
let index = 0;
|
|
3256
|
+
for (const item of this) {
|
|
3257
|
+
if (!predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
3258
|
+
return false;
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
return true;
|
|
3262
|
+
}
|
|
3263
|
+
/**
|
|
3264
|
+
* Test whether any entry satisfies the predicate.
|
|
3265
|
+
* @param predicate - `(key, value, index, self) => boolean`.
|
|
3266
|
+
* @param thisArg - Optional `this` for callback.
|
|
3267
|
+
* @returns `true` if any passes; otherwise `false`.
|
|
3268
|
+
* @remarks Time O(n), Space O(1)
|
|
3269
|
+
*/
|
|
3270
|
+
some(predicate, thisArg) {
|
|
3271
|
+
let index = 0;
|
|
3272
|
+
for (const item of this) {
|
|
3273
|
+
if (predicate.call(thisArg, item[1], item[0], index++, this)) {
|
|
3274
|
+
return true;
|
|
3275
|
+
}
|
|
3276
|
+
}
|
|
3277
|
+
return false;
|
|
3278
|
+
}
|
|
3279
|
+
/**
|
|
3280
|
+
* Visit each entry, left-to-right.
|
|
3281
|
+
* @param callbackfn - `(key, value, index, self) => void`.
|
|
3282
|
+
* @param thisArg - Optional `this` for callback.
|
|
3283
|
+
* @remarks Time O(n), Space O(1)
|
|
3284
|
+
*/
|
|
3285
|
+
forEach(callbackfn, thisArg) {
|
|
3286
|
+
let index = 0;
|
|
3287
|
+
for (const item of this) {
|
|
3288
|
+
const [key, value] = item;
|
|
3289
|
+
callbackfn.call(thisArg, value, key, index++, this);
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
/**
|
|
3293
|
+
* Find the first entry that matches a predicate.
|
|
3294
|
+
* @param callbackfn - `(key, value, index, self) => boolean`.
|
|
3295
|
+
* @param thisArg - Optional `this` for callback.
|
|
3296
|
+
* @returns Matching `[key, value]` or `undefined`.
|
|
3297
|
+
* @remarks Time O(n), Space O(1)
|
|
3298
|
+
*/
|
|
3299
|
+
find(callbackfn, thisArg) {
|
|
3300
|
+
let index = 0;
|
|
3301
|
+
for (const item of this) {
|
|
3302
|
+
const [key, value] = item;
|
|
3303
|
+
if (callbackfn.call(thisArg, value, key, index++, this)) return item;
|
|
3304
|
+
}
|
|
3305
|
+
return;
|
|
3306
|
+
}
|
|
3307
|
+
/**
|
|
3308
|
+
* Whether the given key exists.
|
|
3309
|
+
* @param key - Key to test.
|
|
3310
|
+
* @returns `true` if found; otherwise `false`.
|
|
3311
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
3312
|
+
*/
|
|
3313
|
+
has(key) {
|
|
3314
|
+
for (const item of this) {
|
|
3315
|
+
const [itemKey] = item;
|
|
3316
|
+
if (itemKey === key) return true;
|
|
3317
|
+
}
|
|
3318
|
+
return false;
|
|
3319
|
+
}
|
|
3320
|
+
/**
|
|
3321
|
+
* Whether there exists an entry with the given value.
|
|
3322
|
+
* @param value - Value to test.
|
|
3323
|
+
* @returns `true` if found; otherwise `false`.
|
|
3324
|
+
* @remarks Time O(n), Space O(1)
|
|
3325
|
+
*/
|
|
3326
|
+
hasValue(value) {
|
|
3327
|
+
for (const [, elementValue] of this) {
|
|
3328
|
+
if (elementValue === value) return true;
|
|
3329
|
+
}
|
|
3330
|
+
return false;
|
|
3331
|
+
}
|
|
3332
|
+
/**
|
|
3333
|
+
* Get the value under a key.
|
|
3334
|
+
* @param key - Key to look up.
|
|
3335
|
+
* @returns Value or `undefined`.
|
|
3336
|
+
* @remarks Time O(n) generic, Space O(1)
|
|
3337
|
+
*/
|
|
3338
|
+
get(key) {
|
|
3339
|
+
for (const item of this) {
|
|
3340
|
+
const [itemKey, value] = item;
|
|
3341
|
+
if (itemKey === key) return value;
|
|
3342
|
+
}
|
|
3343
|
+
return;
|
|
3344
|
+
}
|
|
3345
|
+
/**
|
|
3346
|
+
* Reduce entries into a single accumulator.
|
|
3347
|
+
* @param callbackfn - `(acc, value, key, index, self) => acc`.
|
|
3348
|
+
* @param initialValue - Initial accumulator.
|
|
3349
|
+
* @returns Final accumulator.
|
|
3350
|
+
* @remarks Time O(n), Space O(1)
|
|
3351
|
+
*/
|
|
3352
|
+
reduce(callbackfn, initialValue) {
|
|
3353
|
+
let accumulator = initialValue;
|
|
3354
|
+
let index = 0;
|
|
3355
|
+
for (const item of this) {
|
|
3356
|
+
const [key, value] = item;
|
|
3357
|
+
accumulator = callbackfn(accumulator, value, key, index++, this);
|
|
3358
|
+
}
|
|
3359
|
+
return accumulator;
|
|
3360
|
+
}
|
|
3361
|
+
/**
|
|
3362
|
+
* Converts data structure to `[key, value]` pairs.
|
|
3363
|
+
* @returns Array of entries.
|
|
3364
|
+
* @remarks Time O(n), Space O(n)
|
|
3365
|
+
*/
|
|
3366
|
+
toArray() {
|
|
3367
|
+
return [...this];
|
|
3368
|
+
}
|
|
3369
|
+
/**
|
|
3370
|
+
* Visualize the iterable as an array of `[key, value]` pairs (or a custom string).
|
|
3371
|
+
* @returns Array of entries (default) or a string.
|
|
3372
|
+
* @remarks Time O(n), Space O(n)
|
|
3373
|
+
*/
|
|
3374
|
+
toVisual() {
|
|
3375
|
+
return [...this];
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Print a human-friendly representation to the console.
|
|
3379
|
+
* @remarks Time O(n), Space O(n)
|
|
3380
|
+
*/
|
|
3381
|
+
print() {
|
|
3382
|
+
console.log(this.toVisual());
|
|
3383
|
+
}
|
|
3384
|
+
};
|
|
3385
|
+
|
|
1989
3386
|
// src/data-structures/linked-list/skip-linked-list.ts
|
|
1990
3387
|
var SkipListNode = class {
|
|
1991
3388
|
static {
|
|
@@ -1997,136 +3394,1033 @@ var SkipListNode = class {
|
|
|
1997
3394
|
constructor(key, value, level) {
|
|
1998
3395
|
this.key = key;
|
|
1999
3396
|
this.value = value;
|
|
2000
|
-
this.forward = new Array(level);
|
|
3397
|
+
this.forward = new Array(level).fill(void 0);
|
|
2001
3398
|
}
|
|
2002
3399
|
};
|
|
2003
|
-
var SkipList = class {
|
|
3400
|
+
var SkipList = class _SkipList extends IterableEntryBase {
|
|
2004
3401
|
static {
|
|
2005
3402
|
__name(this, "SkipList");
|
|
2006
3403
|
}
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
if (
|
|
2014
|
-
|
|
3404
|
+
#comparator;
|
|
3405
|
+
#isDefaultComparator;
|
|
3406
|
+
constructor(entries = [], options = {}) {
|
|
3407
|
+
super();
|
|
3408
|
+
const { comparator, toEntryFn, maxLevel, probability } = options;
|
|
3409
|
+
if (typeof maxLevel === "number" && maxLevel > 0) this._maxLevel = maxLevel;
|
|
3410
|
+
if (typeof probability === "number" && probability > 0 && probability < 1) this._probability = probability;
|
|
3411
|
+
this.#isDefaultComparator = comparator === void 0;
|
|
3412
|
+
this.#comparator = comparator ?? _SkipList.createDefaultComparator();
|
|
3413
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
3414
|
+
for (const item of entries) {
|
|
3415
|
+
let k;
|
|
3416
|
+
let v;
|
|
3417
|
+
if (toEntryFn) {
|
|
3418
|
+
[k, v] = toEntryFn(item);
|
|
3419
|
+
} else {
|
|
3420
|
+
if (!Array.isArray(item) || item.length < 2) {
|
|
3421
|
+
throw new TypeError(ERR.invalidEntry("SkipList"));
|
|
3422
|
+
}
|
|
3423
|
+
[k, v] = item;
|
|
3424
|
+
}
|
|
3425
|
+
this.set(k, v);
|
|
2015
3426
|
}
|
|
2016
3427
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
3428
|
+
/**
|
|
3429
|
+
* Creates a default comparator supporting number, string, Date, and bigint.
|
|
3430
|
+
*/
|
|
3431
|
+
static createDefaultComparator() {
|
|
3432
|
+
return (a, b) => {
|
|
3433
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
3434
|
+
if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN("SkipList"));
|
|
3435
|
+
return a - b;
|
|
3436
|
+
}
|
|
3437
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
3438
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3439
|
+
}
|
|
3440
|
+
if (a instanceof Date && b instanceof Date) {
|
|
3441
|
+
const ta = a.getTime(), tb = b.getTime();
|
|
3442
|
+
if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate("SkipList"));
|
|
3443
|
+
return ta - tb;
|
|
3444
|
+
}
|
|
3445
|
+
if (typeof a === "bigint" && typeof b === "bigint") {
|
|
3446
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
3447
|
+
}
|
|
3448
|
+
throw new TypeError(ERR.comparatorRequired("SkipList"));
|
|
3449
|
+
};
|
|
2020
3450
|
}
|
|
3451
|
+
// ─── Internal state ──────────────────────────────────────────
|
|
3452
|
+
_head;
|
|
2021
3453
|
_level = 0;
|
|
2022
|
-
|
|
2023
|
-
return this._level;
|
|
2024
|
-
}
|
|
3454
|
+
_size = 0;
|
|
2025
3455
|
_maxLevel = 16;
|
|
3456
|
+
_probability = 0.5;
|
|
3457
|
+
// ─── Size & lifecycle ────────────────────────────────────────
|
|
3458
|
+
get size() {
|
|
3459
|
+
return this._size;
|
|
3460
|
+
}
|
|
2026
3461
|
get maxLevel() {
|
|
2027
3462
|
return this._maxLevel;
|
|
2028
3463
|
}
|
|
2029
|
-
_probability = 0.5;
|
|
2030
3464
|
get probability() {
|
|
2031
3465
|
return this._probability;
|
|
2032
3466
|
}
|
|
2033
|
-
get
|
|
2034
|
-
|
|
2035
|
-
return firstNode ? firstNode.value : void 0;
|
|
3467
|
+
get comparator() {
|
|
3468
|
+
return this.#comparator;
|
|
2036
3469
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
3470
|
+
/**
|
|
3471
|
+
* Check if empty
|
|
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
|
+
|
|
3500
|
+
|
|
3501
|
+
* @example
|
|
3502
|
+
* // Check if empty
|
|
3503
|
+
* const sl = new SkipList<number, string>();
|
|
3504
|
+
* console.log(sl.isEmpty()); // true;
|
|
3505
|
+
*/
|
|
3506
|
+
isEmpty() {
|
|
3507
|
+
return this._size === 0;
|
|
2045
3508
|
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
3509
|
+
/**
|
|
3510
|
+
* Remove all entries
|
|
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
|
+
|
|
3539
|
+
|
|
3540
|
+
* @example
|
|
3541
|
+
* // Remove all entries
|
|
3542
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
3543
|
+
* sl.clear();
|
|
3544
|
+
* console.log(sl.isEmpty()); // true;
|
|
3545
|
+
*/
|
|
3546
|
+
clear() {
|
|
3547
|
+
this._head = new SkipListNode(void 0, void 0, this._maxLevel);
|
|
3548
|
+
this._level = 0;
|
|
3549
|
+
this._size = 0;
|
|
3550
|
+
}
|
|
3551
|
+
/**
|
|
3552
|
+
* Create independent copy
|
|
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
|
+
|
|
3581
|
+
|
|
3582
|
+
* @example
|
|
3583
|
+
* // Create independent copy
|
|
3584
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
3585
|
+
* const copy = sl.clone();
|
|
3586
|
+
* copy.delete(1);
|
|
3587
|
+
* console.log(sl.has(1)); // true;
|
|
3588
|
+
*/
|
|
3589
|
+
clone() {
|
|
3590
|
+
return new _SkipList(this, {
|
|
3591
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
3592
|
+
maxLevel: this._maxLevel,
|
|
3593
|
+
probability: this._probability
|
|
3594
|
+
});
|
|
3595
|
+
}
|
|
3596
|
+
// ─── Core CRUD ───────────────────────────────────────────────
|
|
3597
|
+
/**
|
|
3598
|
+
* Insert or update a key-value pair. Returns `this` for chaining.
|
|
3599
|
+
* Unique keys only — if key exists, value is updated in place.
|
|
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
|
+
|
|
3631
|
+
|
|
3632
|
+
* @example
|
|
3633
|
+
* // In-memory sorted key-value store
|
|
3634
|
+
* const store = new SkipList<number, string>();
|
|
3635
|
+
*
|
|
3636
|
+
* store.set(3, 'three');
|
|
3637
|
+
* store.set(1, 'one');
|
|
3638
|
+
* store.set(5, 'five');
|
|
3639
|
+
* store.set(2, 'two');
|
|
3640
|
+
*
|
|
3641
|
+
* console.log(store.get(3)); // 'three';
|
|
3642
|
+
* console.log(store.get(1)); // 'one';
|
|
3643
|
+
* console.log(store.get(5)); // 'five';
|
|
3644
|
+
*
|
|
3645
|
+
* // Update existing key
|
|
3646
|
+
* store.set(3, 'THREE');
|
|
3647
|
+
* console.log(store.get(3)); // 'THREE';
|
|
3648
|
+
*/
|
|
3649
|
+
set(key, value) {
|
|
3650
|
+
const cmp = this.#comparator;
|
|
3651
|
+
const update = this._findUpdate(key);
|
|
3652
|
+
const existing = update[0].forward[0];
|
|
3653
|
+
if (existing && cmp(existing.key, key) === 0) {
|
|
3654
|
+
existing.value = value;
|
|
3655
|
+
return this;
|
|
3656
|
+
}
|
|
3657
|
+
const newLevel = this._randomLevel();
|
|
3658
|
+
const newNode = new SkipListNode(key, value, newLevel);
|
|
3659
|
+
if (newLevel > this._level) {
|
|
3660
|
+
for (let i = this._level; i < newLevel; i++) {
|
|
3661
|
+
update[i] = this._head;
|
|
2053
3662
|
}
|
|
2054
|
-
|
|
3663
|
+
this._level = newLevel;
|
|
2055
3664
|
}
|
|
2056
|
-
for (let i = 0; i <
|
|
3665
|
+
for (let i = 0; i < newLevel; i++) {
|
|
2057
3666
|
newNode.forward[i] = update[i].forward[i];
|
|
2058
3667
|
update[i].forward[i] = newNode;
|
|
2059
3668
|
}
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
}
|
|
3669
|
+
this._size++;
|
|
3670
|
+
return this;
|
|
2063
3671
|
}
|
|
3672
|
+
/**
|
|
3673
|
+
* Get the value for a key, or `undefined` if not found.
|
|
3674
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
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
|
+
|
|
3706
|
+
|
|
3707
|
+
* @example
|
|
3708
|
+
* // Building a sorted index
|
|
3709
|
+
* type Product = { id: number; name: string; price: number };
|
|
3710
|
+
* const products: Product[] = [
|
|
3711
|
+
* { id: 1, name: 'Widget', price: 25 },
|
|
3712
|
+
* { id: 2, name: 'Gadget', price: 50 },
|
|
3713
|
+
* { id: 3, name: 'Doohickey', price: 15 }
|
|
3714
|
+
* ];
|
|
3715
|
+
*
|
|
3716
|
+
* const index = new SkipList<number, Product, Product>(products, {
|
|
3717
|
+
* toEntryFn: (p: Product) => [p.price, p]
|
|
3718
|
+
* });
|
|
3719
|
+
*
|
|
3720
|
+
* // Iterate in sorted order by price
|
|
3721
|
+
* const names = [...index.values()].map(p => p!.name);
|
|
3722
|
+
* console.log(names); // ['Doohickey', 'Widget', 'Gadget'];
|
|
3723
|
+
*
|
|
3724
|
+
* // Range search: products between $20 and $60
|
|
3725
|
+
* const range = index.rangeSearch([20, 60]);
|
|
3726
|
+
* console.log(range.map(([, p]) => p!.name)); // ['Widget', 'Gadget'];
|
|
3727
|
+
*/
|
|
2064
3728
|
get(key) {
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
while (current.forward[i] && current.forward[i].key < key) {
|
|
2068
|
-
current = current.forward[i];
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
current = current.forward[0];
|
|
2072
|
-
if (current && current.key === key) {
|
|
2073
|
-
return current.value;
|
|
2074
|
-
}
|
|
2075
|
-
return void 0;
|
|
3729
|
+
const node = this._findNode(key);
|
|
3730
|
+
return node ? node.value : void 0;
|
|
2076
3731
|
}
|
|
3732
|
+
/**
|
|
3733
|
+
* Check if a key exists.
|
|
3734
|
+
* Overrides base O(n) with O(log n) skip-list search.
|
|
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
|
+
|
|
3766
|
+
|
|
3767
|
+
* @example
|
|
3768
|
+
* // Check key existence
|
|
3769
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [3, 'c'], [5, 'e']]);
|
|
3770
|
+
* console.log(sl.has(3)); // true;
|
|
3771
|
+
* console.log(sl.has(4)); // false;
|
|
3772
|
+
*/
|
|
2077
3773
|
has(key) {
|
|
2078
|
-
return this.
|
|
3774
|
+
return this._findNode(key) !== void 0;
|
|
2079
3775
|
}
|
|
3776
|
+
/**
|
|
3777
|
+
* Delete a key. Returns `true` if the key was found and removed.
|
|
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
|
+
|
|
3809
|
+
|
|
3810
|
+
* @example
|
|
3811
|
+
* // Fast lookup with deletion
|
|
3812
|
+
* const cache = new SkipList<string, number>();
|
|
3813
|
+
*
|
|
3814
|
+
* cache.set('alpha', 1);
|
|
3815
|
+
* cache.set('beta', 2);
|
|
3816
|
+
* cache.set('gamma', 3);
|
|
3817
|
+
*
|
|
3818
|
+
* console.log(cache.has('beta')); // true;
|
|
3819
|
+
* cache.delete('beta');
|
|
3820
|
+
* console.log(cache.has('beta')); // false;
|
|
3821
|
+
* console.log(cache.size); // 2;
|
|
3822
|
+
*/
|
|
2080
3823
|
delete(key) {
|
|
2081
|
-
const
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
3824
|
+
const cmp = this.#comparator;
|
|
3825
|
+
const update = this._findUpdate(key);
|
|
3826
|
+
const target = update[0].forward[0];
|
|
3827
|
+
if (!target || cmp(target.key, key) !== 0) return false;
|
|
3828
|
+
for (let i = 0; i < this._level; i++) {
|
|
3829
|
+
if (update[i].forward[i] !== target) break;
|
|
3830
|
+
update[i].forward[i] = target.forward[i];
|
|
3831
|
+
}
|
|
3832
|
+
while (this._level > 0 && !this._head.forward[this._level - 1]) {
|
|
3833
|
+
this._level--;
|
|
3834
|
+
}
|
|
3835
|
+
this._size--;
|
|
3836
|
+
return true;
|
|
3837
|
+
}
|
|
3838
|
+
// ─── Navigation ──────────────────────────────────────────────
|
|
3839
|
+
/**
|
|
3840
|
+
* Returns the first (smallest key) entry, or `undefined` if empty.
|
|
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
|
+
|
|
3872
|
+
|
|
3873
|
+
* @example
|
|
3874
|
+
* // Access the minimum entry
|
|
3875
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3876
|
+
* console.log(sl.first()); // [1, 'a'];
|
|
3877
|
+
*/
|
|
3878
|
+
first() {
|
|
3879
|
+
const node = this._head.forward[0];
|
|
3880
|
+
return node ? [node.key, node.value] : void 0;
|
|
3881
|
+
}
|
|
3882
|
+
/**
|
|
3883
|
+
* Returns the last (largest key) entry, or `undefined` if empty.
|
|
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
|
+
|
|
3915
|
+
|
|
3916
|
+
* @example
|
|
3917
|
+
* // Access the maximum entry
|
|
3918
|
+
* const sl = new SkipList<number, string>([[5, 'e'], [1, 'a'], [3, 'c']]);
|
|
3919
|
+
* console.log(sl.last()); // [5, 'e'];
|
|
3920
|
+
*/
|
|
3921
|
+
last() {
|
|
3922
|
+
let current = this._head;
|
|
3923
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
3924
|
+
while (current.forward[i]) {
|
|
2085
3925
|
current = current.forward[i];
|
|
2086
3926
|
}
|
|
2087
|
-
update[i] = current;
|
|
2088
3927
|
}
|
|
2089
|
-
current
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
3928
|
+
return current === this._head ? void 0 : [current.key, current.value];
|
|
3929
|
+
}
|
|
3930
|
+
/**
|
|
3931
|
+
* Remove and return the first (smallest key) entry.
|
|
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
|
+
|
|
3960
|
+
|
|
3961
|
+
* @example
|
|
3962
|
+
* // Remove and return smallest
|
|
3963
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
3964
|
+
* console.log(sl.pollFirst()); // [1, 'a'];
|
|
3965
|
+
* console.log(sl.size); // 2;
|
|
3966
|
+
*/
|
|
3967
|
+
pollFirst() {
|
|
3968
|
+
const entry = this.first();
|
|
3969
|
+
if (!entry) return void 0;
|
|
3970
|
+
this.delete(entry[0]);
|
|
3971
|
+
return entry;
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* Remove and return the last (largest key) entry.
|
|
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
|
+
|
|
4003
|
+
|
|
4004
|
+
* @example
|
|
4005
|
+
* // Remove and return largest
|
|
4006
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
4007
|
+
* console.log(sl.pollLast()); // [3, 'c'];
|
|
4008
|
+
* console.log(sl.size); // 2;
|
|
4009
|
+
*/
|
|
4010
|
+
pollLast() {
|
|
4011
|
+
const entry = this.last();
|
|
4012
|
+
if (!entry) return void 0;
|
|
4013
|
+
this.delete(entry[0]);
|
|
4014
|
+
return entry;
|
|
4015
|
+
}
|
|
4016
|
+
/**
|
|
4017
|
+
* Least entry ≥ key, or `undefined`.
|
|
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
|
+
|
|
4049
|
+
|
|
4050
|
+
* @example
|
|
4051
|
+
* // Least entry ≥ key
|
|
4052
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4053
|
+
* console.log(sl.ceiling(15)); // [20, 'b'];
|
|
4054
|
+
* console.log(sl.ceiling(20)); // [20, 'b'];
|
|
4055
|
+
*/
|
|
4056
|
+
ceiling(key) {
|
|
4057
|
+
const cmp = this.#comparator;
|
|
4058
|
+
let current = this._head;
|
|
4059
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4060
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4061
|
+
current = current.forward[i];
|
|
2096
4062
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
4063
|
+
}
|
|
4064
|
+
const node = current.forward[0];
|
|
4065
|
+
return node ? [node.key, node.value] : void 0;
|
|
4066
|
+
}
|
|
4067
|
+
/**
|
|
4068
|
+
* Greatest entry ≤ key, or `undefined`.
|
|
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
|
+
|
|
4100
|
+
|
|
4101
|
+
* @example
|
|
4102
|
+
* // Greatest entry ≤ key
|
|
4103
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4104
|
+
* console.log(sl.floor(25)); // [20, 'b'];
|
|
4105
|
+
* console.log(sl.floor(5)); // undefined;
|
|
4106
|
+
*/
|
|
4107
|
+
floor(key) {
|
|
4108
|
+
const cmp = this.#comparator;
|
|
4109
|
+
let current = this._head;
|
|
4110
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4111
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
4112
|
+
current = current.forward[i];
|
|
2099
4113
|
}
|
|
2100
|
-
return true;
|
|
2101
4114
|
}
|
|
2102
|
-
|
|
4115
|
+
const result = current === this._head ? void 0 : current;
|
|
4116
|
+
if (result && cmp(result.key, key) <= 0) return [result.key, result.value];
|
|
4117
|
+
return void 0;
|
|
2103
4118
|
}
|
|
4119
|
+
/**
|
|
4120
|
+
* Least entry strictly > key, or `undefined`.
|
|
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
|
+
|
|
4149
|
+
|
|
4150
|
+
* @example
|
|
4151
|
+
* // Strictly greater entry
|
|
4152
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4153
|
+
* console.log(sl.higher(15)); // [20, 'b'];
|
|
4154
|
+
* console.log(sl.higher(30)); // undefined;
|
|
4155
|
+
*/
|
|
2104
4156
|
higher(key) {
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
4157
|
+
const cmp = this.#comparator;
|
|
4158
|
+
let current = this._head;
|
|
4159
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4160
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) <= 0) {
|
|
2108
4161
|
current = current.forward[i];
|
|
2109
4162
|
}
|
|
2110
4163
|
}
|
|
2111
|
-
const
|
|
2112
|
-
return
|
|
4164
|
+
const node = current.forward[0];
|
|
4165
|
+
return node ? [node.key, node.value] : void 0;
|
|
2113
4166
|
}
|
|
4167
|
+
/**
|
|
4168
|
+
* Greatest entry strictly < key, or `undefined`.
|
|
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
|
+
|
|
4197
|
+
|
|
4198
|
+
* @example
|
|
4199
|
+
* // Strictly less entry
|
|
4200
|
+
* const sl = new SkipList<number, string>([[10, 'a'], [20, 'b'], [30, 'c']]);
|
|
4201
|
+
* console.log(sl.lower(25)); // [20, 'b'];
|
|
4202
|
+
* console.log(sl.lower(10)); // undefined;
|
|
4203
|
+
*/
|
|
2114
4204
|
lower(key) {
|
|
2115
|
-
|
|
2116
|
-
let
|
|
2117
|
-
|
|
2118
|
-
|
|
4205
|
+
const cmp = this.#comparator;
|
|
4206
|
+
let current = this._head;
|
|
4207
|
+
let result;
|
|
4208
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4209
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4210
|
+
current = current.forward[i];
|
|
4211
|
+
}
|
|
4212
|
+
if (current !== this._head && cmp(current.key, key) < 0) {
|
|
4213
|
+
result = current;
|
|
4214
|
+
}
|
|
4215
|
+
}
|
|
4216
|
+
return result ? [result.key, result.value] : void 0;
|
|
4217
|
+
}
|
|
4218
|
+
/**
|
|
4219
|
+
* Returns entries within the given key range.
|
|
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
|
+
|
|
4251
|
+
|
|
4252
|
+
* @example
|
|
4253
|
+
* // Find entries in a range
|
|
4254
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c'], [4, 'd'], [5, 'e']]);
|
|
4255
|
+
* const result = sl.rangeSearch([2, 4]);
|
|
4256
|
+
* console.log(result); // [[2, 'b'], [3, 'c'], [4, 'd']];
|
|
4257
|
+
*/
|
|
4258
|
+
rangeSearch(range, options = {}) {
|
|
4259
|
+
const { lowInclusive = true, highInclusive = true } = options;
|
|
4260
|
+
const [low, high] = range;
|
|
4261
|
+
const cmp = this.#comparator;
|
|
4262
|
+
const out = [];
|
|
4263
|
+
let current = this._head;
|
|
4264
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4265
|
+
while (current.forward[i] && cmp(current.forward[i].key, low) < 0) {
|
|
4266
|
+
current = current.forward[i];
|
|
4267
|
+
}
|
|
4268
|
+
}
|
|
4269
|
+
current = current.forward[0];
|
|
4270
|
+
while (current) {
|
|
4271
|
+
const cmpHigh = cmp(current.key, high);
|
|
4272
|
+
if (cmpHigh > 0) break;
|
|
4273
|
+
if (cmpHigh === 0 && !highInclusive) break;
|
|
4274
|
+
const cmpLow = cmp(current.key, low);
|
|
4275
|
+
if (cmpLow > 0 || cmpLow === 0 && lowInclusive) {
|
|
4276
|
+
out.push([current.key, current.value]);
|
|
4277
|
+
}
|
|
4278
|
+
current = current.forward[0];
|
|
4279
|
+
}
|
|
4280
|
+
return out;
|
|
4281
|
+
}
|
|
4282
|
+
// ─── Functional (overrides) ──────────────────────────────────
|
|
4283
|
+
/**
|
|
4284
|
+
* Creates a new SkipList with entries transformed by callback.
|
|
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
|
+
|
|
4313
|
+
|
|
4314
|
+
* @example
|
|
4315
|
+
* // Transform entries
|
|
4316
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b']]);
|
|
4317
|
+
* const mapped = sl.map((v, k) => [k, v?.toUpperCase()] as [number, string]);
|
|
4318
|
+
* console.log([...mapped.values()]); // ['A', 'B'];
|
|
4319
|
+
*/
|
|
4320
|
+
map(callback, options) {
|
|
4321
|
+
const out = new _SkipList([], options ?? {});
|
|
4322
|
+
let i = 0;
|
|
4323
|
+
for (const [k, v] of this) {
|
|
4324
|
+
const [nk, nv] = callback(v, k, i++, this);
|
|
4325
|
+
out.set(nk, nv);
|
|
4326
|
+
}
|
|
4327
|
+
return out;
|
|
4328
|
+
}
|
|
4329
|
+
/**
|
|
4330
|
+
* Creates a new SkipList with entries that pass the predicate.
|
|
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
|
+
|
|
4359
|
+
|
|
4360
|
+
* @example
|
|
4361
|
+
* // Filter entries
|
|
4362
|
+
* const sl = new SkipList<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
4363
|
+
* const result = sl.filter((v, k) => k > 1);
|
|
4364
|
+
* console.log(result.size); // 2;
|
|
4365
|
+
*/
|
|
4366
|
+
filter(callbackfn, thisArg) {
|
|
4367
|
+
const out = new _SkipList([], {
|
|
4368
|
+
comparator: this.#isDefaultComparator ? void 0 : this.#comparator,
|
|
4369
|
+
maxLevel: this._maxLevel,
|
|
4370
|
+
probability: this._probability
|
|
4371
|
+
});
|
|
4372
|
+
let i = 0;
|
|
4373
|
+
for (const [k, v] of this) {
|
|
4374
|
+
const ok = callbackfn.call(thisArg, v, k, i++, this);
|
|
4375
|
+
if (ok) out.set(k, v);
|
|
4376
|
+
}
|
|
4377
|
+
return out;
|
|
4378
|
+
}
|
|
4379
|
+
// ─── Iterator (required by IterableEntryBase) ────────────────
|
|
4380
|
+
_getIterator() {
|
|
4381
|
+
const head = this._head;
|
|
4382
|
+
return (function* () {
|
|
4383
|
+
let node = head.forward[0];
|
|
4384
|
+
while (node) {
|
|
4385
|
+
yield [node.key, node.value];
|
|
4386
|
+
node = node.forward[0];
|
|
4387
|
+
}
|
|
4388
|
+
})();
|
|
4389
|
+
}
|
|
4390
|
+
// ─── Internal helpers ────────────────────────────────────────
|
|
4391
|
+
/**
|
|
4392
|
+
* Finds the update array (predecessors at each level) for a given key.
|
|
4393
|
+
*/
|
|
4394
|
+
_findUpdate(key) {
|
|
4395
|
+
const cmp = this.#comparator;
|
|
4396
|
+
const update = new Array(this._maxLevel).fill(this._head);
|
|
4397
|
+
let current = this._head;
|
|
4398
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4399
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
2119
4400
|
current = current.forward[i];
|
|
2120
4401
|
}
|
|
2121
|
-
|
|
2122
|
-
|
|
4402
|
+
update[i] = current;
|
|
4403
|
+
}
|
|
4404
|
+
return update;
|
|
4405
|
+
}
|
|
4406
|
+
/**
|
|
4407
|
+
* Finds the node for a given key, or undefined.
|
|
4408
|
+
*/
|
|
4409
|
+
_findNode(key) {
|
|
4410
|
+
const cmp = this.#comparator;
|
|
4411
|
+
let current = this._head;
|
|
4412
|
+
for (let i = this._level - 1; i >= 0; i--) {
|
|
4413
|
+
while (current.forward[i] && cmp(current.forward[i].key, key) < 0) {
|
|
4414
|
+
current = current.forward[i];
|
|
2123
4415
|
}
|
|
2124
4416
|
}
|
|
2125
|
-
|
|
4417
|
+
const candidate = current.forward[0];
|
|
4418
|
+
if (candidate && cmp(candidate.key, key) === 0) return candidate;
|
|
4419
|
+
return void 0;
|
|
2126
4420
|
}
|
|
2127
4421
|
_randomLevel() {
|
|
2128
4422
|
let level = 1;
|
|
2129
|
-
while (Math.random() < this.
|
|
4423
|
+
while (Math.random() < this._probability && level < this._maxLevel) {
|
|
2130
4424
|
level++;
|
|
2131
4425
|
}
|
|
2132
4426
|
return level;
|