atomic-fns 0.3.1 → 0.3.3
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/.esdoc.json +2 -2
- package/README.md +48 -13
- package/core/collections/BTree.d.ts +229 -0
- package/core/collections/BTree.js +1165 -0
- package/core/collections/BTree.ts +1340 -0
- package/core/collections/Heap.d.ts +69 -0
- package/core/collections/Heap.js +181 -0
- package/core/collections/Heap.ts +189 -0
- package/core/collections/LRUCache.d.ts +131 -0
- package/core/collections/LRUCache.js +388 -0
- package/core/collections/LRUCache.ts +465 -0
- package/core/collections/SortedMap.d.ts +92 -0
- package/core/collections/SortedMap.js +130 -0
- package/core/collections/SortedMap.ts +146 -0
- package/core/collections/SortedSet.d.ts +63 -0
- package/core/collections/SortedSet.js +93 -0
- package/core/collections/SortedSet.ts +104 -0
- package/core/collections/SortedTree.d.ts +103 -0
- package/core/collections/SortedTree.js +141 -0
- package/core/collections/SortedTree.ts +160 -0
- package/core/collections/SplayTree.d.ts +105 -0
- package/core/collections/SplayTree.js +338 -0
- package/core/collections/SplayTree.ts +354 -0
- package/core/collections/abc.d.ts +152 -0
- package/core/collections/abc.js +39 -0
- package/core/collections/abc.ts +176 -0
- package/core/collections/deque.d.ts +110 -0
- package/core/collections/deque.js +285 -0
- package/core/collections/deque.ts +329 -0
- package/core/collections/frozenset.d.ts +19 -0
- package/core/collections/frozenset.js +33 -0
- package/core/collections/frozenset.ts +37 -0
- package/{src → core}/collections/index.d.ts +41 -162
- package/{src → core}/collections/index.js +57 -165
- package/{src → core}/collections/index.ts +61 -225
- package/core/collections/test.html +10 -0
- package/core/collections/typedArrays.d.ts +31 -0
- package/core/collections/typedArrays.js +143 -0
- package/core/collections/typedArrays.ts +163 -0
- package/core/datetime/index.d.ts +45 -0
- package/core/datetime/index.js +71 -0
- package/core/datetime/index.ts +128 -0
- package/{src → core}/functools/index.d.ts +2 -2
- package/{src → core}/functools/index.js +2 -2
- package/{src → core}/functools/index.ts +2 -2
- package/{src → core}/globals/index.d.ts +2 -7
- package/{src → core}/globals/index.js +5 -2
- package/{src → core}/globals/index.ts +6 -9
- package/{src → core}/index.d.ts +0 -1
- package/{src → core}/index.js +0 -1
- package/{src → core}/index.ts +0 -1
- package/{src → core}/itertools/index.d.ts +9 -7
- package/{src → core}/itertools/index.js +25 -9
- package/{src → core}/itertools/index.ts +39 -16
- package/{src → core}/math/index.d.ts +0 -0
- package/{src → core}/math/index.js +0 -0
- package/{src → core}/math/index.ts +0 -0
- package/core/operators/index.d.ts +148 -0
- package/core/operators/index.js +271 -0
- package/core/operators/index.ts +282 -0
- package/{src → core}/random/index.d.ts +0 -0
- package/{src → core}/random/index.js +0 -0
- package/{src → core}/random/index.ts +0 -0
- package/package.json +6 -6
- package/tests/BTree.spec.ts +143 -0
- package/tests/Cache.spec.ts +161 -0
- package/tests/Heap.spec.ts +66 -0
- package/tests/SortedMap.spec.ts +144 -0
- package/tests/SortedSet.spec.ts +84 -0
- package/tests/SortedTree.spec.ts +164 -0
- package/tests/SplayTree.spec.ts +121 -0
- package/tests/collections.spec.ts +1 -1
- package/tests/deque.spec.ts +107 -0
- package/tests/globals.spec.ts +2 -2
- package/tests/itertools.spec.ts +2 -2
- package/tests/math.spec.ts +1 -1
- package/tests/operators.spec.ts +5 -5
- package/tests/random.spec.ts +10 -10
- package/tsconfig.json +10 -10
- package/tsconfig.node.json +2 -2
- package/tsconfig.xo.json +2 -2
- package/src/datetime/index.d.ts +0 -6
- package/src/datetime/index.js +0 -6
- package/src/datetime/index.ts +0 -7
- package/src/operators/index.d.ts +0 -31
- package/src/operators/index.js +0 -171
- package/src/operators/index.ts +0 -175
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Comparer } from '../operators/index.js'
|
|
2
|
+
import { Mapping } from './abc.js'
|
|
3
|
+
import { BTree } from './BTree.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A `SortedTree` is a map that holds key value pairs in sorted orders of keys. Any primitive value (and objects that implement a `compare` or `lt` methods) can be used as keys or values.
|
|
7
|
+
* @see {@link Operators.compare}
|
|
8
|
+
* @see {@link Operators.lt}
|
|
9
|
+
* @template K, V
|
|
10
|
+
*/
|
|
11
|
+
export class SortedTree<K, V> extends Mapping<K, V> {
|
|
12
|
+
private readonly store: BTree<K, V>
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new `SortedTree` object.
|
|
16
|
+
* @param {Iterable<[K, V]>} [iterable] Initialize the tree with entries.
|
|
17
|
+
* @param {Comparer} [compareFn] The `compare` function to sort keys.
|
|
18
|
+
*/
|
|
19
|
+
constructor(iterable?: Iterable<[K, V]>, compareFn?: Comparer) {
|
|
20
|
+
super()
|
|
21
|
+
this.store = new BTree<K, V>(iterable, compareFn)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Adds a new `key` with a `null` value.
|
|
26
|
+
* @param {K} key
|
|
27
|
+
* @returns {this} Returns the Tree object.
|
|
28
|
+
*/
|
|
29
|
+
add(key: K) {
|
|
30
|
+
this.store.set(key, null as V)
|
|
31
|
+
return this
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Returns the value associated with the `key` or `undefined`.
|
|
36
|
+
* @param {K} key
|
|
37
|
+
* @returns {?V} The key value or `undefined`.
|
|
38
|
+
*/
|
|
39
|
+
get(key: K) {
|
|
40
|
+
return this.store.get(key)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Sets the value for the given `key`.
|
|
45
|
+
* @param {K} key
|
|
46
|
+
* @param {V} value
|
|
47
|
+
* @returns {this} Returns the Tree object.
|
|
48
|
+
*/
|
|
49
|
+
set(key: K, value: V) {
|
|
50
|
+
this.store.set(key, value)
|
|
51
|
+
return this
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns the smallest key in the tree.
|
|
56
|
+
* @returns {?K}
|
|
57
|
+
*/
|
|
58
|
+
min() {
|
|
59
|
+
return this.store.minKey()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Returns the largest key in the tree.
|
|
64
|
+
* @returns {?K}
|
|
65
|
+
*/
|
|
66
|
+
max() {
|
|
67
|
+
return this.store.maxKey()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Returns `true` if the `key` existed in the tree and was removed.
|
|
72
|
+
* @param {K} key
|
|
73
|
+
* @returns {boolean} `true` if key was removed, otherwise `false`.
|
|
74
|
+
*/
|
|
75
|
+
delete(key: K) {
|
|
76
|
+
return this.store.remove(key)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Removes all key/value pairs in the tree.
|
|
81
|
+
*/
|
|
82
|
+
clear() {
|
|
83
|
+
return this.store.clear()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Freezes the tree which prevents adding, updating or removing any keys.
|
|
88
|
+
* @returns {this}
|
|
89
|
+
*/
|
|
90
|
+
freeze() {
|
|
91
|
+
this.store.freeze()
|
|
92
|
+
return this
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Returns a new iterator of `[K, V]` pairs in reverse order of keys.
|
|
97
|
+
* @returns {Iterable<[K, V]>}
|
|
98
|
+
*/
|
|
99
|
+
reversed() {
|
|
100
|
+
return this.store.reversed()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Returns the total key/value pairs in the tree.
|
|
105
|
+
* @returns {number}
|
|
106
|
+
*/
|
|
107
|
+
get size() {
|
|
108
|
+
return this.store.size
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if there are no key/value pairs in the tree.
|
|
113
|
+
* @returns {boolean} `true` if is empty.
|
|
114
|
+
*/
|
|
115
|
+
empty() {
|
|
116
|
+
return this.store.empty()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Returns `true` if the `key` exists in the tree.
|
|
121
|
+
* @param {K} key
|
|
122
|
+
* @returns {boolean} `true` if key is found, otherwise `false`.
|
|
123
|
+
*/
|
|
124
|
+
contains(key: K) {
|
|
125
|
+
return this.store.contains(key)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Returns `true` if the `key` exists in the tree.
|
|
130
|
+
* @param {K} key
|
|
131
|
+
* @returns {boolean} `true` if key is found, otherwise `false`.
|
|
132
|
+
*/
|
|
133
|
+
has(key: K) {
|
|
134
|
+
return this.store.contains(key)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Returns a new iterator of all **ordered** keys in the tree.
|
|
139
|
+
* @returns {Iterable<K>}
|
|
140
|
+
*/
|
|
141
|
+
keys() {
|
|
142
|
+
return this.store.keys()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Returns a new iterator of all values **ordered** by their keys.
|
|
147
|
+
* @returns {Iterable<V>}
|
|
148
|
+
*/
|
|
149
|
+
values() {
|
|
150
|
+
return this.store.values()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Returns a new iterator of all key value pairs **ordered** by their keys.
|
|
155
|
+
* @returns {Iterable<[K, V]>}
|
|
156
|
+
*/
|
|
157
|
+
entries() {
|
|
158
|
+
return this.store.entries()
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Comparer } from '../operators/index.js';
|
|
2
|
+
import { Mapping } from './abc.js';
|
|
3
|
+
/**
|
|
4
|
+
* Base SplayTree node class.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
declare class Node<K = any, V = any> {
|
|
8
|
+
key: K;
|
|
9
|
+
value: V;
|
|
10
|
+
left?: Node<K, V>;
|
|
11
|
+
right?: Node<K, V>;
|
|
12
|
+
constructor(key: K, value: V);
|
|
13
|
+
get height(): any;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A splay tree is a *self-balancing binary* search tree with the additional property that recently accessed elements are quick to access again.
|
|
17
|
+
* Insertion, look-up and removal in O(log n) *amortized* time.
|
|
18
|
+
* For many patterns of non-random operations splay trees can take better than logarithmic time, without requiring advance knowledge of the pattern.
|
|
19
|
+
* @see {@link https://en.wikipedia.org/wiki/Splay_tree Splay tree}
|
|
20
|
+
* @see {@link https://web.archive.org/web/20220930173835/http://www14.in.tum.de/personen/albers/papers/ipl02.pdf Randomized Splay Trees}
|
|
21
|
+
* @template K, V
|
|
22
|
+
*/
|
|
23
|
+
export declare class SplayTree<K, V = any> extends Mapping<K, V> {
|
|
24
|
+
protected root?: Node<K, V>;
|
|
25
|
+
protected cmp: Comparer;
|
|
26
|
+
protected randSplay: number;
|
|
27
|
+
protected count: number;
|
|
28
|
+
/**
|
|
29
|
+
* Create a new randomized Splay Tree
|
|
30
|
+
* @param compareFn
|
|
31
|
+
* @param p When an element is accessed, with probability `p` splay the tree. With probability `1 - p`, leave the tree as it is.
|
|
32
|
+
*/
|
|
33
|
+
constructor(compareFn?: any, p?: number);
|
|
34
|
+
top(): K | undefined;
|
|
35
|
+
get size(): number;
|
|
36
|
+
empty(): boolean;
|
|
37
|
+
get height(): any;
|
|
38
|
+
/**
|
|
39
|
+
* Returns the value for `key` or `undefined` if the key is not found.
|
|
40
|
+
* @param key The key to find.
|
|
41
|
+
* @returns {?V} The value for the key or `undefined`.
|
|
42
|
+
*/
|
|
43
|
+
get(key: K): any;
|
|
44
|
+
/**
|
|
45
|
+
* Inserts the `key` and `value` in the tree if the `key` does not exist.
|
|
46
|
+
* @param {K} key A key which can be any comparable value
|
|
47
|
+
* @param {V} value A value associated with the key
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
set(key: K, value: V): void;
|
|
51
|
+
/**
|
|
52
|
+
* Removes a specified key if it exists in the tree. The removed value is returned or `undefined` if not found.
|
|
53
|
+
* @param {K} key The key to remove.
|
|
54
|
+
* @returns {V} The removed value associated with `key`.
|
|
55
|
+
*/
|
|
56
|
+
remove(key: K): V | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Returns the minimum key in the tree or subtree.
|
|
59
|
+
* @returns The minimum key.
|
|
60
|
+
*/
|
|
61
|
+
min(root?: Node<K, V> | undefined): K | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Returns the maximum key in the tree or subtree.
|
|
64
|
+
* @returns The maximum key.
|
|
65
|
+
*/
|
|
66
|
+
max(root?: Node<K, V> | undefined): K | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the largest key that is less than a given key.
|
|
69
|
+
* @param key The given key
|
|
70
|
+
* @returns The largest key found or `undefined`.
|
|
71
|
+
*/
|
|
72
|
+
lowerBound(key: any): K | Node<K, V> | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* This is the simplified top-down splaying method proposed by Sleator and Tarjan in {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}.
|
|
75
|
+
* @param key
|
|
76
|
+
* @see {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}
|
|
77
|
+
*/
|
|
78
|
+
splay(key: any): void;
|
|
79
|
+
add(key: K): void;
|
|
80
|
+
/**
|
|
81
|
+
* Returns `true` if the given key is in the tree.
|
|
82
|
+
* @param {K} key The key to find.
|
|
83
|
+
* @returns `true` if found.
|
|
84
|
+
*/
|
|
85
|
+
contains(key: K): boolean;
|
|
86
|
+
/** Alias of remove but just returns `true` instead of the deleted value. */
|
|
87
|
+
delete(key: K): boolean;
|
|
88
|
+
clear(): void;
|
|
89
|
+
/**
|
|
90
|
+
* Returns an ordered iterable of all the keys in the tree.
|
|
91
|
+
* @returns {Iterable<K>} An iterable of keys in-order.
|
|
92
|
+
*/
|
|
93
|
+
keys(): Iterable<K>;
|
|
94
|
+
/**
|
|
95
|
+
* Returns an ordered iterable of all the keys and values in the tree.
|
|
96
|
+
* @returns {Iterable<[K,V]>} A iterable of `[key, value]` pairs sorted by key.
|
|
97
|
+
*/
|
|
98
|
+
entries(): Iterable<[K, V]>;
|
|
99
|
+
/**
|
|
100
|
+
* Returns an ordered iterable of all the keys and values in the tree.
|
|
101
|
+
* @returns {Iterable<V>} A iterable of `[key, value]` pairs sorted by key.
|
|
102
|
+
*/
|
|
103
|
+
values(): Iterable<V>;
|
|
104
|
+
}
|
|
105
|
+
export {};
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { compare, eq } from '../operators/index.js';
|
|
2
|
+
import { Mapping } from './abc.js';
|
|
3
|
+
/**
|
|
4
|
+
* Base SplayTree node class.
|
|
5
|
+
* @private
|
|
6
|
+
*/
|
|
7
|
+
class Node {
|
|
8
|
+
key;
|
|
9
|
+
value;
|
|
10
|
+
left;
|
|
11
|
+
right;
|
|
12
|
+
constructor(key, value) {
|
|
13
|
+
this.key = key;
|
|
14
|
+
this.value = value;
|
|
15
|
+
}
|
|
16
|
+
get height() {
|
|
17
|
+
if (this.left && this.right)
|
|
18
|
+
return 1 + Math.max(this.right.height, this.left.height);
|
|
19
|
+
if (this.right)
|
|
20
|
+
return 1 + this.right.height;
|
|
21
|
+
if (this.left)
|
|
22
|
+
return 1 + this.left.height;
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// In-order traversal of a tree
|
|
27
|
+
function* traverse(node) {
|
|
28
|
+
while (node) {
|
|
29
|
+
yield* traverse(node.left);
|
|
30
|
+
yield node;
|
|
31
|
+
node = node.right;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A splay tree is a *self-balancing binary* search tree with the additional property that recently accessed elements are quick to access again.
|
|
36
|
+
* Insertion, look-up and removal in O(log n) *amortized* time.
|
|
37
|
+
* For many patterns of non-random operations splay trees can take better than logarithmic time, without requiring advance knowledge of the pattern.
|
|
38
|
+
* @see {@link https://en.wikipedia.org/wiki/Splay_tree Splay tree}
|
|
39
|
+
* @see {@link https://web.archive.org/web/20220930173835/http://www14.in.tum.de/personen/albers/papers/ipl02.pdf Randomized Splay Trees}
|
|
40
|
+
* @template K, V
|
|
41
|
+
*/
|
|
42
|
+
export class SplayTree extends Mapping {
|
|
43
|
+
root;
|
|
44
|
+
cmp;
|
|
45
|
+
randSplay;
|
|
46
|
+
count;
|
|
47
|
+
/**
|
|
48
|
+
* Create a new randomized Splay Tree
|
|
49
|
+
* @param compareFn
|
|
50
|
+
* @param p When an element is accessed, with probability `p` splay the tree. With probability `1 - p`, leave the tree as it is.
|
|
51
|
+
*/
|
|
52
|
+
constructor(compareFn, p = 0.5) {
|
|
53
|
+
super();
|
|
54
|
+
this.cmp = compareFn ?? compare;
|
|
55
|
+
this.count = 0;
|
|
56
|
+
this.randSplay = p;
|
|
57
|
+
}
|
|
58
|
+
top() {
|
|
59
|
+
return this.root?.key;
|
|
60
|
+
}
|
|
61
|
+
get size() {
|
|
62
|
+
return this.count;
|
|
63
|
+
}
|
|
64
|
+
empty() {
|
|
65
|
+
return !this.root;
|
|
66
|
+
}
|
|
67
|
+
get height() {
|
|
68
|
+
if (!this.root)
|
|
69
|
+
return 0;
|
|
70
|
+
return this.root.height;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns the value for `key` or `undefined` if the key is not found.
|
|
74
|
+
* @param key The key to find.
|
|
75
|
+
* @returns {?V} The value for the key or `undefined`.
|
|
76
|
+
*/
|
|
77
|
+
get(key) {
|
|
78
|
+
if (!this.root)
|
|
79
|
+
return;
|
|
80
|
+
// Note: deterministic splaying (always moves key to front):
|
|
81
|
+
// this.splay(key)
|
|
82
|
+
// if (this.cmp(key, this.root.key) === 0) return this.root.value
|
|
83
|
+
// Randomized Splay Trees https://doi.org/10.1016%2Fs0020-0190%2801%2900230-7
|
|
84
|
+
// The randomized idea is only moving accessed keys with a certain probability `p`.
|
|
85
|
+
// Values of `p` closer to 1 tend to perform well.
|
|
86
|
+
if (Math.random() <= this.randSplay) {
|
|
87
|
+
this.splay(key);
|
|
88
|
+
if (this.cmp(key, this.root.key) === 0)
|
|
89
|
+
return this.root.value;
|
|
90
|
+
else
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
// Lookup the node down the tree
|
|
94
|
+
let current = this.root;
|
|
95
|
+
while (current) {
|
|
96
|
+
const rank = this.cmp(key, current.key);
|
|
97
|
+
if (rank === 0)
|
|
98
|
+
return current.value;
|
|
99
|
+
if (rank < 0)
|
|
100
|
+
current = current.left;
|
|
101
|
+
else
|
|
102
|
+
current = current.right;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Inserts the `key` and `value` in the tree if the `key` does not exist.
|
|
107
|
+
* @param {K} key A key which can be any comparable value
|
|
108
|
+
* @param {V} value A value associated with the key
|
|
109
|
+
* @returns
|
|
110
|
+
*/
|
|
111
|
+
set(key, value) {
|
|
112
|
+
if (!this.root) {
|
|
113
|
+
this.root = new Node(key, value);
|
|
114
|
+
this.count += 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Splay on the key to move the last node on the search path for
|
|
118
|
+
// the key to the root of the tree.
|
|
119
|
+
this.splay(key);
|
|
120
|
+
const rank = this.cmp(key, this.root.key);
|
|
121
|
+
if (rank === 0) {
|
|
122
|
+
// Update the value
|
|
123
|
+
this.root.value = value;
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const node = new Node(key, value);
|
|
127
|
+
if (rank > 0) {
|
|
128
|
+
node.left = this.root;
|
|
129
|
+
node.right = this.root.right;
|
|
130
|
+
this.root.right = undefined;
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
node.right = this.root;
|
|
134
|
+
node.left = this.root.left;
|
|
135
|
+
this.root.left = undefined;
|
|
136
|
+
}
|
|
137
|
+
this.root = node;
|
|
138
|
+
this.count += 1;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Removes a specified key if it exists in the tree. The removed value is returned or `undefined` if not found.
|
|
142
|
+
* @param {K} key The key to remove.
|
|
143
|
+
* @returns {V} The removed value associated with `key`.
|
|
144
|
+
*/
|
|
145
|
+
remove(key) {
|
|
146
|
+
if (!this.root) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.splay(key);
|
|
150
|
+
if (!eq(key, this.root.key)) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const removed = this.root;
|
|
154
|
+
if (!this.root.left) {
|
|
155
|
+
this.root = this.root.right;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const right = this.root.right;
|
|
159
|
+
this.root = this.root.left;
|
|
160
|
+
//
|
|
161
|
+
// Splay to make sure that the new root has an empty right child.
|
|
162
|
+
//
|
|
163
|
+
this.splay(key);
|
|
164
|
+
//
|
|
165
|
+
// Insert the original right child as the right child of the new
|
|
166
|
+
// root.
|
|
167
|
+
//
|
|
168
|
+
this.root.right = right;
|
|
169
|
+
}
|
|
170
|
+
this.count -= 1;
|
|
171
|
+
return removed.value;
|
|
172
|
+
}
|
|
173
|
+
//
|
|
174
|
+
// function find(key)
|
|
175
|
+
// @param {number} key Key to find in the tree.
|
|
176
|
+
// @return {SplayTree.Node} Node having the specified key.
|
|
177
|
+
//
|
|
178
|
+
//
|
|
179
|
+
/**
|
|
180
|
+
* Returns the minimum key in the tree or subtree.
|
|
181
|
+
* @returns The minimum key.
|
|
182
|
+
*/
|
|
183
|
+
min(root = this.root) {
|
|
184
|
+
if (!root)
|
|
185
|
+
return;
|
|
186
|
+
while (root.left) {
|
|
187
|
+
root = root.left;
|
|
188
|
+
}
|
|
189
|
+
return root.key;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Returns the maximum key in the tree or subtree.
|
|
193
|
+
* @returns The maximum key.
|
|
194
|
+
*/
|
|
195
|
+
max(root = this.root) {
|
|
196
|
+
if (!root)
|
|
197
|
+
return;
|
|
198
|
+
while (root.right) {
|
|
199
|
+
root = root.right;
|
|
200
|
+
}
|
|
201
|
+
return root.key;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns the largest key that is less than a given key.
|
|
205
|
+
* @param key The given key
|
|
206
|
+
* @returns The largest key found or `undefined`.
|
|
207
|
+
*/
|
|
208
|
+
lowerBound(key) {
|
|
209
|
+
if (!this.root)
|
|
210
|
+
return;
|
|
211
|
+
// Splay on the key to move the node with the given key or the last
|
|
212
|
+
// node on the search path to the top of the tree.
|
|
213
|
+
this.splay(key);
|
|
214
|
+
// Now the result is either the root node or the greatest node in
|
|
215
|
+
// the left subtree.
|
|
216
|
+
if (this.cmp(this.root.key, key) < 0) {
|
|
217
|
+
return this.root;
|
|
218
|
+
}
|
|
219
|
+
else if (this.root.left) {
|
|
220
|
+
return this.max(this.root.left);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* This is the simplified top-down splaying method proposed by Sleator and Tarjan in {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}.
|
|
225
|
+
* @param key
|
|
226
|
+
* @see {@link https://doi.org/10.1145%2F3828.3835 Self-Adjusting Binary Search Trees}
|
|
227
|
+
*/
|
|
228
|
+
splay(key) {
|
|
229
|
+
if (!this.root)
|
|
230
|
+
return;
|
|
231
|
+
let stub, left, right;
|
|
232
|
+
// eslint-disable-next-line
|
|
233
|
+
stub = left = right = new Node(null, null);
|
|
234
|
+
let root = this.root;
|
|
235
|
+
while (true) {
|
|
236
|
+
const rank = this.cmp(key, root.key);
|
|
237
|
+
if (rank < 0) {
|
|
238
|
+
if (!root.left) {
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
if (this.cmp(key, root.left.key) < 0) {
|
|
242
|
+
// Rotate right.
|
|
243
|
+
const tmp = root.left;
|
|
244
|
+
root.left = tmp.right;
|
|
245
|
+
tmp.right = root;
|
|
246
|
+
root = tmp;
|
|
247
|
+
if (!root.left) {
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Link right.
|
|
252
|
+
right.left = root;
|
|
253
|
+
right = root;
|
|
254
|
+
root = root.left;
|
|
255
|
+
}
|
|
256
|
+
else if (rank > 0) {
|
|
257
|
+
if (!root.right) {
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
if (this.cmp(key, root.right.key) > 0) {
|
|
261
|
+
// Rotate left.
|
|
262
|
+
const tmp = root.right;
|
|
263
|
+
root.right = tmp.left;
|
|
264
|
+
tmp.left = root;
|
|
265
|
+
root = tmp;
|
|
266
|
+
if (!root.right) {
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Link left.
|
|
271
|
+
left.right = root;
|
|
272
|
+
left = root;
|
|
273
|
+
root = root.right;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
// Assemble.
|
|
280
|
+
left.right = root.left;
|
|
281
|
+
right.left = root.right;
|
|
282
|
+
root.left = stub.right;
|
|
283
|
+
root.right = stub.left;
|
|
284
|
+
this.root = root;
|
|
285
|
+
}
|
|
286
|
+
add(key) {
|
|
287
|
+
return this.set(key, null);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Returns `true` if the given key is in the tree.
|
|
291
|
+
* @param {K} key The key to find.
|
|
292
|
+
* @returns `true` if found.
|
|
293
|
+
*/
|
|
294
|
+
contains(key) {
|
|
295
|
+
return this.get(key) !== undefined;
|
|
296
|
+
}
|
|
297
|
+
/** Alias of remove but just returns `true` instead of the deleted value. */
|
|
298
|
+
delete(key) {
|
|
299
|
+
// since remove throws, this will throw too
|
|
300
|
+
this.remove(key);
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
clear() {
|
|
304
|
+
if (!this.root)
|
|
305
|
+
return;
|
|
306
|
+
this.root.left = undefined;
|
|
307
|
+
this.root.right = undefined;
|
|
308
|
+
this.root = undefined;
|
|
309
|
+
this.count = 0;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Returns an ordered iterable of all the keys in the tree.
|
|
313
|
+
* @returns {Iterable<K>} An iterable of keys in-order.
|
|
314
|
+
*/
|
|
315
|
+
*keys() {
|
|
316
|
+
for (const node of traverse(this.root)) {
|
|
317
|
+
yield node.key;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Returns an ordered iterable of all the keys and values in the tree.
|
|
322
|
+
* @returns {Iterable<[K,V]>} A iterable of `[key, value]` pairs sorted by key.
|
|
323
|
+
*/
|
|
324
|
+
*entries() {
|
|
325
|
+
for (const node of traverse(this.root)) {
|
|
326
|
+
yield [node.key, node.value];
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Returns an ordered iterable of all the keys and values in the tree.
|
|
331
|
+
* @returns {Iterable<V>} A iterable of `[key, value]` pairs sorted by key.
|
|
332
|
+
*/
|
|
333
|
+
*values() {
|
|
334
|
+
for (const node of traverse(this.root)) {
|
|
335
|
+
yield node.value;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|