list-toolkit 2.0.0 → 2.1.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 +4 -2
- package/cjs/heap/min-heap.js +21 -51
- package/cjs/list/nodes.js +2 -2
- package/cjs/meta-utils.js +7 -3
- package/cjs/slist/nodes.js +1 -1
- package/cjs/tree/splay-tree.js +362 -0
- package/package.json +18 -8
- package/src/heap/min-heap.js +21 -52
- package/src/list/nodes.js +3 -3
- package/src/meta-utils.js +4 -2
- package/src/slist/nodes.js +2 -2
- package/src/tree/splay-tree.js +378 -0
package/README.md
CHANGED
|
@@ -101,8 +101,8 @@ const john = new Person('John'),
|
|
|
101
101
|
|
|
102
102
|
const people = List.from([john, jane, jim, jill]);
|
|
103
103
|
|
|
104
|
-
//
|
|
105
|
-
for (let node = people.front; node !== people; node = node[
|
|
104
|
+
// iterate over the list manually:
|
|
105
|
+
for (let node = people.front; node !== people; node = node[people.nextName]) {
|
|
106
106
|
console.log(node.name); // John, Jane, Jim, Jill
|
|
107
107
|
}
|
|
108
108
|
// yes, the link names are customizable, can be strings or symbols, for example:
|
|
@@ -146,6 +146,8 @@ BSD 3-Clause "New" or "Revised" License. See the LICENSE file for details.
|
|
|
146
146
|
|
|
147
147
|
## Release History
|
|
148
148
|
|
|
149
|
+
* 2.1.1 *Allowed functions to be used as nodes. Updated deps.*
|
|
150
|
+
* 2.1.0 *Added splay tree. Updated deps.*
|
|
149
151
|
* 2.0.0 *New major release.*
|
|
150
152
|
* 1.0.1 *Fixed exports. Added more methods to `MinHeap`.*
|
|
151
153
|
* 1.0.1 *Initial release.*
|
package/cjs/heap/min-heap.js
CHANGED
|
@@ -27,17 +27,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
27
27
|
for (;;) {
|
|
28
28
|
const l = (i << 1) + 1;
|
|
29
29
|
if (l >= n) break;
|
|
30
|
-
|
|
30
|
+
const r = l + 1,
|
|
31
|
+
c = r < n && less(array[r], array[l]) ? r : l,
|
|
32
|
+
iValue = array[i],
|
|
31
33
|
cValue = array[c];
|
|
32
|
-
const r = c + 1;
|
|
33
|
-
if (r < n) {
|
|
34
|
-
const rValue = array[r];
|
|
35
|
-
if (less(rValue, cValue)) {
|
|
36
|
-
c = r;
|
|
37
|
-
cValue = rValue;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
const iValue = array[i];
|
|
41
34
|
if (!less(cValue, iValue)) break;
|
|
42
35
|
array[i] = cValue;
|
|
43
36
|
array[c] = iValue;
|
|
@@ -48,6 +41,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
48
41
|
class MinHeap {
|
|
49
42
|
constructor(options, ...args) {
|
|
50
43
|
(0, _metaUtils.copyOptions)(this, MinHeap.defaults, options);
|
|
44
|
+
if (typeof this.compare == 'function') {
|
|
45
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
46
|
+
this.equal = (a, b) => !this.compare(a, b);
|
|
47
|
+
}
|
|
51
48
|
this.array = [];
|
|
52
49
|
this.merge(...args);
|
|
53
50
|
}
|
|
@@ -78,17 +75,10 @@ class MinHeap {
|
|
|
78
75
|
for (let i = 0;;) {
|
|
79
76
|
const l = (i << 1) + 1;
|
|
80
77
|
if (l >= n) break;
|
|
81
|
-
|
|
78
|
+
const r = l + 1,
|
|
79
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
80
|
+
iValue = this.array[i],
|
|
82
81
|
cValue = this.array[c];
|
|
83
|
-
const r = c + 1;
|
|
84
|
-
if (r < n) {
|
|
85
|
-
const rValue = this.array[r];
|
|
86
|
-
if (this.less(rValue, cValue)) {
|
|
87
|
-
c = r;
|
|
88
|
-
cValue = rValue;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
const iValue = this.array[i];
|
|
92
82
|
if (!this.less(cValue, iValue)) break;
|
|
93
83
|
this.array[i] = cValue;
|
|
94
84
|
this.array[c] = iValue;
|
|
@@ -120,17 +110,10 @@ class MinHeap {
|
|
|
120
110
|
for (let i = 0;;) {
|
|
121
111
|
const l = (i << 1) + 1;
|
|
122
112
|
if (l >= n) break;
|
|
123
|
-
|
|
113
|
+
const r = l + 1,
|
|
114
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
115
|
+
iValue = this.array[i],
|
|
124
116
|
cValue = this.array[c];
|
|
125
|
-
const r = c + 1;
|
|
126
|
-
if (r < n) {
|
|
127
|
-
const rValue = this.array[r];
|
|
128
|
-
if (this.less(rValue, cValue)) {
|
|
129
|
-
c = r;
|
|
130
|
-
cValue = rValue;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const iValue = this.array[i];
|
|
134
117
|
if (!this.less(cValue, iValue)) break;
|
|
135
118
|
this.array[i] = cValue;
|
|
136
119
|
this.array[c] = iValue;
|
|
@@ -147,17 +130,10 @@ class MinHeap {
|
|
|
147
130
|
for (let i = 0;;) {
|
|
148
131
|
const l = (i << 1) + 1;
|
|
149
132
|
if (l >= n) break;
|
|
150
|
-
|
|
133
|
+
const r = l + 1,
|
|
134
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
135
|
+
iValue = this.array[i],
|
|
151
136
|
cValue = this.array[c];
|
|
152
|
-
const r = c + 1;
|
|
153
|
-
if (r < n) {
|
|
154
|
-
const rValue = this.array[r];
|
|
155
|
-
if (this.less(rValue, cValue)) {
|
|
156
|
-
c = r;
|
|
157
|
-
cValue = rValue;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
const iValue = this.array[i];
|
|
161
137
|
if (!this.less(cValue, iValue)) break;
|
|
162
138
|
this.array[i] = cValue;
|
|
163
139
|
this.array[c] = iValue;
|
|
@@ -230,17 +206,10 @@ class MinHeap {
|
|
|
230
206
|
for (let i = j;;) {
|
|
231
207
|
const l = (i << 1) + 1;
|
|
232
208
|
if (l >= n) break;
|
|
233
|
-
|
|
209
|
+
const r = l + 1,
|
|
210
|
+
c = r < n && less(array[r], array[l]) ? r : l,
|
|
211
|
+
iValue = array[i],
|
|
234
212
|
cValue = array[c];
|
|
235
|
-
const r = c + 1;
|
|
236
|
-
if (r < n) {
|
|
237
|
-
const rValue = array[r];
|
|
238
|
-
if (less(rValue, cValue)) {
|
|
239
|
-
c = r;
|
|
240
|
-
cValue = rValue;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
const iValue = array[i];
|
|
244
213
|
if (!less(cValue, iValue)) break;
|
|
245
214
|
array[i] = cValue;
|
|
246
215
|
array[c] = iValue;
|
|
@@ -323,6 +292,7 @@ class MinHeap {
|
|
|
323
292
|
exports.MinHeap = MinHeap;
|
|
324
293
|
MinHeap.defaults = {
|
|
325
294
|
less: defaultLess,
|
|
326
|
-
equal: defaultEqual
|
|
295
|
+
equal: defaultEqual,
|
|
296
|
+
compare: null
|
|
327
297
|
};
|
|
328
298
|
var _default = exports.default = MinHeap;
|
package/cjs/list/nodes.js
CHANGED
|
@@ -36,9 +36,9 @@ class HeadNode extends Node {
|
|
|
36
36
|
isNodeLike(node) {
|
|
37
37
|
if (!node) return false;
|
|
38
38
|
const next = node[this.nextName];
|
|
39
|
-
if (!next || typeof next
|
|
39
|
+
if (!next || _metaUtils.canHaveProps[typeof next] !== 1) return false;
|
|
40
40
|
const prev = node[this.prevName];
|
|
41
|
-
return prev && typeof prev
|
|
41
|
+
return prev && _metaUtils.canHaveProps[typeof prev] === 1;
|
|
42
42
|
}
|
|
43
43
|
isCompatibleNames({
|
|
44
44
|
nextName,
|
package/cjs/meta-utils.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.toSnakeCase = exports.toPascalCase = exports.toKebabCase = exports.toCamelCase = exports.toAllCapsSnakeCase = exports.normalizeIterator = exports.mapIterator = exports.fromSnakeCase = exports.fromSetter = exports.fromPascalCase = exports.fromKebabCase = exports.fromGetter = exports.fromCamelCase = exports.fromAccessors = exports.defaultDescriptor = exports.copyOptions = exports.copyDescriptors = exports.capitalize = exports.augmentIterator = exports.addGetters = exports.addDescriptors = exports.addDescriptor = exports.addAliases = exports.addAlias = exports.addAccessor = void 0;
|
|
6
|
+
exports.toSnakeCase = exports.toPascalCase = exports.toKebabCase = exports.toCamelCase = exports.toAllCapsSnakeCase = exports.normalizeIterator = exports.mapIterator = exports.fromSnakeCase = exports.fromSetter = exports.fromPascalCase = exports.fromKebabCase = exports.fromGetter = exports.fromCamelCase = exports.fromAccessors = exports.defaultDescriptor = exports.copyOptions = exports.copyDescriptors = exports.capitalize = exports.canHaveProps = exports.augmentIterator = exports.addGetters = exports.addDescriptors = exports.addDescriptor = exports.addAliases = exports.addAlias = exports.addAccessor = void 0;
|
|
7
7
|
const capitalize = name => name ? name[0].toUpperCase() + name.substring(1).toLowerCase() : name;
|
|
8
8
|
exports.capitalize = capitalize;
|
|
9
9
|
const toCamelCase = names => names.map((name, index) => index ? capitalize(name) : name.toLowerCase()).join('');
|
|
@@ -119,7 +119,7 @@ exports.addAlias = addAlias;
|
|
|
119
119
|
const addAliases = (object, dict, force) => copyDescriptors(object, object, dict, force);
|
|
120
120
|
exports.addAliases = addAliases;
|
|
121
121
|
const augmentIterator = iterator => {
|
|
122
|
-
if (!
|
|
122
|
+
if (!iterator.hasOwnProperty(Symbol.iterator)) {
|
|
123
123
|
iterator[Symbol.iterator] = function () {
|
|
124
124
|
return this;
|
|
125
125
|
};
|
|
@@ -150,6 +150,10 @@ const mapIterator = (iterator, callbackFn) => {
|
|
|
150
150
|
};
|
|
151
151
|
};
|
|
152
152
|
exports.mapIterator = mapIterator;
|
|
153
|
+
const canHaveProps = exports.canHaveProps = {
|
|
154
|
+
object: 1,
|
|
155
|
+
function: 1
|
|
156
|
+
};
|
|
153
157
|
const copyOptions = (target, pattern, ...sources) => {
|
|
154
158
|
target = target || {};
|
|
155
159
|
const keys = Object.keys(pattern);
|
|
@@ -157,7 +161,7 @@ const copyOptions = (target, pattern, ...sources) => {
|
|
|
157
161
|
target[key] = pattern[key];
|
|
158
162
|
}
|
|
159
163
|
for (const source of sources) {
|
|
160
|
-
if (!source || typeof source !==
|
|
164
|
+
if (!source || canHaveProps[typeof source] !== 1) continue;
|
|
161
165
|
for (const key of keys) {
|
|
162
166
|
if (key in source) target[key] = source[key];
|
|
163
167
|
}
|
package/cjs/slist/nodes.js
CHANGED
|
@@ -36,7 +36,7 @@ class HeadNode extends Node {
|
|
|
36
36
|
isNodeLike(node) {
|
|
37
37
|
if (!node) return false;
|
|
38
38
|
const next = node[this.nextName];
|
|
39
|
-
return next && typeof next
|
|
39
|
+
return next && _metaUtils.canHaveProps[typeof next] === 1;
|
|
40
40
|
}
|
|
41
41
|
isCompatibleNames({
|
|
42
42
|
nextName
|
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.SplayTreeNode = exports.SplayTree = void 0;
|
|
7
|
+
var _metaUtils = require("../meta-utils.js");
|
|
8
|
+
const defaultLess = (a, b) => a < b;
|
|
9
|
+
const zig = tree => {
|
|
10
|
+
const newTree = tree.left,
|
|
11
|
+
parent = newTree.parent = tree.parent;
|
|
12
|
+
if (parent) {
|
|
13
|
+
if (parent.left === tree) parent.left = newTree;else parent.right = newTree;
|
|
14
|
+
}
|
|
15
|
+
tree.parent = newTree;
|
|
16
|
+
const child = tree.left = newTree.right;
|
|
17
|
+
if (child) child.parent = tree;
|
|
18
|
+
newTree.right = tree;
|
|
19
|
+
return newTree;
|
|
20
|
+
};
|
|
21
|
+
const zag = tree => {
|
|
22
|
+
const newTree = tree.right,
|
|
23
|
+
parent = newTree.parent = tree.parent;
|
|
24
|
+
if (parent) {
|
|
25
|
+
if (parent.left === tree) parent.left = newTree;else parent.right = newTree;
|
|
26
|
+
}
|
|
27
|
+
tree.parent = newTree;
|
|
28
|
+
const child = tree.right = newTree.left;
|
|
29
|
+
if (child) child.parent = tree;
|
|
30
|
+
newTree.left = tree;
|
|
31
|
+
return newTree;
|
|
32
|
+
};
|
|
33
|
+
const splay = node => {
|
|
34
|
+
while (node.parent) {
|
|
35
|
+
if (!node.parent.parent) {
|
|
36
|
+
node.parent.left === node ? zig(node.parent) : zag(node.parent);
|
|
37
|
+
} else if (node.parent.left === node && node.parent.parent.left === node.parent) {
|
|
38
|
+
zig(node.parent.parent);
|
|
39
|
+
zig(node.parent);
|
|
40
|
+
} else if (node.parent.right === node && node.parent.parent.right === node.parent) {
|
|
41
|
+
zag(node.parent.parent);
|
|
42
|
+
zag(node.parent);
|
|
43
|
+
} else if (node.parent.left === node && node.parent.parent.right === node.parent) {
|
|
44
|
+
zig(node.parent);
|
|
45
|
+
zag(node.parent);
|
|
46
|
+
} else {
|
|
47
|
+
zag(node.parent);
|
|
48
|
+
zig(node.parent);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return node;
|
|
52
|
+
};
|
|
53
|
+
const count = tree => tree ? count(tree.left) + count(tree.right) + 1 : 0;
|
|
54
|
+
class SplayTreeNode {
|
|
55
|
+
constructor(value) {
|
|
56
|
+
this.left = this.right = this.parent = null;
|
|
57
|
+
this.value = value;
|
|
58
|
+
}
|
|
59
|
+
getMin() {
|
|
60
|
+
let z = this;
|
|
61
|
+
while (z.left) z = z.left;
|
|
62
|
+
return z;
|
|
63
|
+
}
|
|
64
|
+
getMax() {
|
|
65
|
+
let z = this;
|
|
66
|
+
while (z.right) z = z.right;
|
|
67
|
+
return z;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.SplayTreeNode = SplayTreeNode;
|
|
71
|
+
class SplayTree {
|
|
72
|
+
constructor(options) {
|
|
73
|
+
(0, _metaUtils.copyOptions)(this, SplayTree.defaults, options);
|
|
74
|
+
if (typeof this.compare == 'function') {
|
|
75
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
76
|
+
this.find = this.findWithCompare;
|
|
77
|
+
this.insert = this.insertWithCompare;
|
|
78
|
+
this.splitMaxTree = this.splitMaxTreeWithCompare;
|
|
79
|
+
}
|
|
80
|
+
this.root = null;
|
|
81
|
+
this.size = 0;
|
|
82
|
+
}
|
|
83
|
+
get isEmpty() {
|
|
84
|
+
return !this.root;
|
|
85
|
+
}
|
|
86
|
+
get length() {
|
|
87
|
+
return this.size;
|
|
88
|
+
}
|
|
89
|
+
getMin() {
|
|
90
|
+
return this.root.getMin();
|
|
91
|
+
}
|
|
92
|
+
getMax() {
|
|
93
|
+
return this.root.getMax();
|
|
94
|
+
}
|
|
95
|
+
find(value) {
|
|
96
|
+
for (let z = this.root; z;) {
|
|
97
|
+
if (this.less(z.value, value)) z = z.right;else if (this.less(value, z.value)) z = z.left;else return z;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
findWithCompare(value) {
|
|
102
|
+
for (let z = this.root; z;) {
|
|
103
|
+
const cmp = this.compare(value, z.value);
|
|
104
|
+
if (cmp < 0) z = z.left;else if (cmp > 0) z = z.right;else return z;
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
promote(value) {
|
|
109
|
+
const z = this.find(value);
|
|
110
|
+
if (z) {
|
|
111
|
+
this.root = splay(z);
|
|
112
|
+
}
|
|
113
|
+
return z;
|
|
114
|
+
}
|
|
115
|
+
splay(node) {
|
|
116
|
+
this.root = splay(node);
|
|
117
|
+
return this;
|
|
118
|
+
}
|
|
119
|
+
insert(value) {
|
|
120
|
+
let z = this.root,
|
|
121
|
+
parent = null;
|
|
122
|
+
while (z) {
|
|
123
|
+
parent = z;
|
|
124
|
+
if (this.less(z.value, value)) z = z.right;else if (this.less(value, z.value)) z = z.left;else break;
|
|
125
|
+
}
|
|
126
|
+
if (!z) {
|
|
127
|
+
z = new SplayTreeNode(value);
|
|
128
|
+
z.parent = parent;
|
|
129
|
+
if (parent) {
|
|
130
|
+
if (this.less(parent.value, value)) parent.right = z;else parent.left = z;
|
|
131
|
+
}
|
|
132
|
+
++this.size;
|
|
133
|
+
}
|
|
134
|
+
this.root = splay(z);
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
insertWithCompare(value) {
|
|
138
|
+
let z = this.root,
|
|
139
|
+
parent = null;
|
|
140
|
+
while (z) {
|
|
141
|
+
parent = z;
|
|
142
|
+
const cmp = this.compare(value, z.value);
|
|
143
|
+
if (cmp < 0) z = z.left;else if (cmp > 0) z = z.right;else break;
|
|
144
|
+
}
|
|
145
|
+
if (!z) {
|
|
146
|
+
z = new SplayTreeNode(value);
|
|
147
|
+
z.parent = parent;
|
|
148
|
+
if (parent) {
|
|
149
|
+
if (this.compare(parent.value, value) < 0) parent.right = z;else parent.left = z;
|
|
150
|
+
}
|
|
151
|
+
++this.size;
|
|
152
|
+
}
|
|
153
|
+
this.root = splay(z);
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
remove(value) {
|
|
157
|
+
const z = this.find(value);
|
|
158
|
+
if (!z) return this;
|
|
159
|
+
splay(z);
|
|
160
|
+
this.root = null;
|
|
161
|
+
let maxNode = null;
|
|
162
|
+
if (z.left) {
|
|
163
|
+
z.left.parent = null;
|
|
164
|
+
maxNode = z.left.getMax();
|
|
165
|
+
this.root = splay(maxNode);
|
|
166
|
+
}
|
|
167
|
+
if (z.right) {
|
|
168
|
+
if (maxNode) maxNode.right = z.right;else this.root = z.right;
|
|
169
|
+
z.right.parent = maxNode;
|
|
170
|
+
}
|
|
171
|
+
--this.size;
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
clear() {
|
|
175
|
+
this.root = null;
|
|
176
|
+
this.size = 0;
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
splitMaxTree(value) {
|
|
180
|
+
if (!this.root) return new SplayTree(this);
|
|
181
|
+
let z = this.root,
|
|
182
|
+
parent = null,
|
|
183
|
+
right;
|
|
184
|
+
while (z) {
|
|
185
|
+
parent = z;
|
|
186
|
+
if (this.less(z.value, value)) {
|
|
187
|
+
z = z.right;
|
|
188
|
+
right = true;
|
|
189
|
+
} else if (this.less(value, z.value)) {
|
|
190
|
+
z = z.left;
|
|
191
|
+
right = false;
|
|
192
|
+
} else break;
|
|
193
|
+
}
|
|
194
|
+
this.root = splay(z || parent);
|
|
195
|
+
const newTree = new SplayTree(this);
|
|
196
|
+
if (z || right) {
|
|
197
|
+
newTree.root = this.root.right;
|
|
198
|
+
if (newTree.root) {
|
|
199
|
+
newTree.root.parent = null;
|
|
200
|
+
newTree.size = count(newTree.root);
|
|
201
|
+
this.root.right = null;
|
|
202
|
+
this.size -= newTree.size;
|
|
203
|
+
}
|
|
204
|
+
} else {
|
|
205
|
+
newTree.root = this.root;
|
|
206
|
+
newTree.size = this.size;
|
|
207
|
+
this.root = this.root.left;
|
|
208
|
+
if (this.root) {
|
|
209
|
+
this.root.parent = null;
|
|
210
|
+
this.size = count(this.root);
|
|
211
|
+
newTree.root.left = null;
|
|
212
|
+
newTree.size -= this.size;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return newTree;
|
|
216
|
+
}
|
|
217
|
+
splitMaxTreeWithCompare(value) {
|
|
218
|
+
if (!this.root) return new SplayTree(this);
|
|
219
|
+
let z = this.root,
|
|
220
|
+
parent = null,
|
|
221
|
+
right;
|
|
222
|
+
while (z) {
|
|
223
|
+
parent = z;
|
|
224
|
+
const cmp = this.compare(value, z.value);
|
|
225
|
+
if (cmp < 0) {
|
|
226
|
+
z = z.left;
|
|
227
|
+
right = false;
|
|
228
|
+
} else if (cmp > 0) {
|
|
229
|
+
z = z.right;
|
|
230
|
+
right = true;
|
|
231
|
+
} else break;
|
|
232
|
+
}
|
|
233
|
+
this.root = splay(z || parent);
|
|
234
|
+
const newTree = new SplayTree(this);
|
|
235
|
+
if (z || right) {
|
|
236
|
+
newTree.root = this.root.right;
|
|
237
|
+
if (newTree.root) {
|
|
238
|
+
newTree.root.parent = null;
|
|
239
|
+
newTree.size = count(newTree.root);
|
|
240
|
+
this.root.right = null;
|
|
241
|
+
this.size -= newTree.size;
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
newTree.root = this.root;
|
|
245
|
+
newTree.size = this.size;
|
|
246
|
+
this.root = this.root.left;
|
|
247
|
+
if (this.root) {
|
|
248
|
+
this.root.parent = null;
|
|
249
|
+
this.size = count(this.root);
|
|
250
|
+
newTree.root.left = null;
|
|
251
|
+
newTree.size -= this.size;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return newTree;
|
|
255
|
+
}
|
|
256
|
+
joinMaxTreeUnsafe(tree) {
|
|
257
|
+
if (this.root.right) {
|
|
258
|
+
this.splay(this.getMax());
|
|
259
|
+
}
|
|
260
|
+
this.root.right = tree.root;
|
|
261
|
+
tree.root.parent = this.root;
|
|
262
|
+
this.size += tree.size;
|
|
263
|
+
tree.clear();
|
|
264
|
+
return this;
|
|
265
|
+
}
|
|
266
|
+
join(tree) {
|
|
267
|
+
if (!tree.root) return this;
|
|
268
|
+
if (!this.root) {
|
|
269
|
+
this.root = tree.root;
|
|
270
|
+
this.size = tree.size;
|
|
271
|
+
tree.clear();
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
const leftMax = this.getMax(),
|
|
275
|
+
rightMin = tree.getMin();
|
|
276
|
+
if (this.less(leftMax.value, rightMin.value)) {
|
|
277
|
+
return this.splay(leftMax).joinMaxTreeUnsafe(tree);
|
|
278
|
+
}
|
|
279
|
+
for (const value of tree) {
|
|
280
|
+
this.insert(value);
|
|
281
|
+
}
|
|
282
|
+
tree.clear();
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
[Symbol.iterator]() {
|
|
286
|
+
let current = this.root ? this.root.getMin() : null;
|
|
287
|
+
return {
|
|
288
|
+
next: () => {
|
|
289
|
+
if (!current) return {
|
|
290
|
+
done: true
|
|
291
|
+
};
|
|
292
|
+
const last = current;
|
|
293
|
+
if (current.right) {
|
|
294
|
+
current = current.right.getMin();
|
|
295
|
+
} else {
|
|
296
|
+
for (;;) {
|
|
297
|
+
const parent = current.parent;
|
|
298
|
+
if (!parent) {
|
|
299
|
+
current = null;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
if (parent.left === current) {
|
|
303
|
+
current = parent;
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
current = parent;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
value: last.value
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
getReverseIterator() {
|
|
316
|
+
return {
|
|
317
|
+
[Symbol.iterator]: () => {
|
|
318
|
+
let current = this.root ? this.root.getMax() : null;
|
|
319
|
+
return {
|
|
320
|
+
next: () => {
|
|
321
|
+
if (!current) return {
|
|
322
|
+
done: true
|
|
323
|
+
};
|
|
324
|
+
const last = current;
|
|
325
|
+
if (current.left) {
|
|
326
|
+
current = current.left.getMax();
|
|
327
|
+
} else {
|
|
328
|
+
for (;;) {
|
|
329
|
+
const parent = current.parent;
|
|
330
|
+
if (!parent) {
|
|
331
|
+
current = null;
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
if (parent.right === current) {
|
|
335
|
+
current = parent;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
current = parent;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return {
|
|
342
|
+
value: last.value
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
static from(values, options) {
|
|
350
|
+
const tree = new SplayTree(options);
|
|
351
|
+
for (const value of values) {
|
|
352
|
+
tree.insert(value);
|
|
353
|
+
}
|
|
354
|
+
return tree;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
exports.SplayTree = SplayTree;
|
|
358
|
+
SplayTree.defaults = {
|
|
359
|
+
less: defaultLess,
|
|
360
|
+
compare: null
|
|
361
|
+
};
|
|
362
|
+
var _default = exports.default = SplayTree;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "list-toolkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "List-based data structures to organize your objects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"test": "tape6 --flags FO",
|
|
14
13
|
"prepare-dist": "node scripts/prepare-dist.js",
|
|
15
14
|
"build": "babel src --out-dir cjs",
|
|
16
|
-
"prepublishOnly": "npm run prepare-dist && npm run build"
|
|
15
|
+
"prepublishOnly": "npm run prepare-dist && npm run build",
|
|
16
|
+
"test": "tape6 --flags FO",
|
|
17
|
+
"test:bun": "tape6-bun --flags FO",
|
|
18
|
+
"test:deno-original": "tape6-deno --flags FO",
|
|
19
|
+
"test:deno": "deno run -A `tape6-runner main` --flags FO",
|
|
20
|
+
"start": "tape6-server --trace"
|
|
17
21
|
},
|
|
18
22
|
"repository": {
|
|
19
23
|
"type": "git",
|
|
@@ -33,10 +37,10 @@
|
|
|
33
37
|
},
|
|
34
38
|
"homepage": "https://github.com/uhop/list-toolkit#readme",
|
|
35
39
|
"devDependencies": {
|
|
36
|
-
"@babel/cli": "^7.
|
|
37
|
-
"@babel/core": "^7.
|
|
38
|
-
"@babel/preset-env": "^7.
|
|
39
|
-
"tape-six": "^0.
|
|
40
|
+
"@babel/cli": "^7.25.6",
|
|
41
|
+
"@babel/core": "^7.25.2",
|
|
42
|
+
"@babel/preset-env": "^7.25.4",
|
|
43
|
+
"tape-six": "^0.12.2"
|
|
40
44
|
},
|
|
41
45
|
"files": [
|
|
42
46
|
"/src",
|
|
@@ -57,6 +61,12 @@
|
|
|
57
61
|
"tape6": {
|
|
58
62
|
"tests": [
|
|
59
63
|
"/tests/test-*.*js"
|
|
60
|
-
]
|
|
64
|
+
],
|
|
65
|
+
"importmap": {
|
|
66
|
+
"imports": {
|
|
67
|
+
"tape-six": "/node_modules/tape-six/index.js",
|
|
68
|
+
"list-toolkit/": "/src/"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
61
71
|
}
|
|
62
72
|
}
|
package/src/heap/min-heap.js
CHANGED
|
@@ -26,17 +26,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
26
26
|
for (;;) {
|
|
27
27
|
const l = (i << 1) + 1;
|
|
28
28
|
if (l >= n) break;
|
|
29
|
-
|
|
29
|
+
const r = l + 1,
|
|
30
|
+
c = r < n && less(array[r], array[l]) ? r : l,
|
|
31
|
+
iValue = array[i],
|
|
30
32
|
cValue = array[c];
|
|
31
|
-
const r = c + 1;
|
|
32
|
-
if (r < n) {
|
|
33
|
-
const rValue = array[r];
|
|
34
|
-
if (less(rValue, cValue)) {
|
|
35
|
-
c = r;
|
|
36
|
-
cValue = rValue;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const iValue = array[i];
|
|
40
33
|
if (!less(cValue, iValue)) break;
|
|
41
34
|
array[i] = cValue;
|
|
42
35
|
array[c] = iValue;
|
|
@@ -48,6 +41,10 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
48
41
|
export class MinHeap {
|
|
49
42
|
constructor(options, ...args) {
|
|
50
43
|
copyOptions(this, MinHeap.defaults, options);
|
|
44
|
+
if (typeof this.compare == 'function') {
|
|
45
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
46
|
+
this.equal = (a, b) => !this.compare(a, b);
|
|
47
|
+
}
|
|
51
48
|
this.array = [];
|
|
52
49
|
this.merge(...args);
|
|
53
50
|
}
|
|
@@ -83,17 +80,10 @@ export class MinHeap {
|
|
|
83
80
|
for (let i = 0; ; ) {
|
|
84
81
|
const l = (i << 1) + 1;
|
|
85
82
|
if (l >= n) break;
|
|
86
|
-
|
|
83
|
+
const r = l + 1,
|
|
84
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
85
|
+
iValue = this.array[i],
|
|
87
86
|
cValue = this.array[c];
|
|
88
|
-
const r = c + 1;
|
|
89
|
-
if (r < n) {
|
|
90
|
-
const rValue = this.array[r];
|
|
91
|
-
if (this.less(rValue, cValue)) {
|
|
92
|
-
c = r;
|
|
93
|
-
cValue = rValue;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
const iValue = this.array[i];
|
|
97
87
|
if (!this.less(cValue, iValue)) break;
|
|
98
88
|
this.array[i] = cValue;
|
|
99
89
|
this.array[c] = iValue;
|
|
@@ -127,17 +117,10 @@ export class MinHeap {
|
|
|
127
117
|
for (let i = 0; ; ) {
|
|
128
118
|
const l = (i << 1) + 1;
|
|
129
119
|
if (l >= n) break;
|
|
130
|
-
|
|
120
|
+
const r = l + 1,
|
|
121
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
122
|
+
iValue = this.array[i],
|
|
131
123
|
cValue = this.array[c];
|
|
132
|
-
const r = c + 1;
|
|
133
|
-
if (r < n) {
|
|
134
|
-
const rValue = this.array[r];
|
|
135
|
-
if (this.less(rValue, cValue)) {
|
|
136
|
-
c = r;
|
|
137
|
-
cValue = rValue;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
const iValue = this.array[i];
|
|
141
124
|
if (!this.less(cValue, iValue)) break;
|
|
142
125
|
this.array[i] = cValue;
|
|
143
126
|
this.array[c] = iValue;
|
|
@@ -155,17 +138,10 @@ export class MinHeap {
|
|
|
155
138
|
for (let i = 0; ; ) {
|
|
156
139
|
const l = (i << 1) + 1;
|
|
157
140
|
if (l >= n) break;
|
|
158
|
-
|
|
141
|
+
const r = l + 1,
|
|
142
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
143
|
+
iValue = this.array[i],
|
|
159
144
|
cValue = this.array[c];
|
|
160
|
-
const r = c + 1;
|
|
161
|
-
if (r < n) {
|
|
162
|
-
const rValue = this.array[r];
|
|
163
|
-
if (this.less(rValue, cValue)) {
|
|
164
|
-
c = r;
|
|
165
|
-
cValue = rValue;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
const iValue = this.array[i];
|
|
169
145
|
if (!this.less(cValue, iValue)) break;
|
|
170
146
|
this.array[i] = cValue;
|
|
171
147
|
this.array[c] = iValue;
|
|
@@ -257,17 +233,10 @@ export class MinHeap {
|
|
|
257
233
|
for (let i = j; ; ) {
|
|
258
234
|
const l = (i << 1) + 1;
|
|
259
235
|
if (l >= n) break;
|
|
260
|
-
|
|
236
|
+
const r = l + 1,
|
|
237
|
+
c = r < n && less(array[r], array[l]) ? r : l,
|
|
238
|
+
iValue = array[i],
|
|
261
239
|
cValue = array[c];
|
|
262
|
-
const r = c + 1;
|
|
263
|
-
if (r < n) {
|
|
264
|
-
const rValue = array[r];
|
|
265
|
-
if (less(rValue, cValue)) {
|
|
266
|
-
c = r;
|
|
267
|
-
cValue = rValue;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
const iValue = array[i];
|
|
271
240
|
if (!less(cValue, iValue)) break;
|
|
272
241
|
array[i] = cValue;
|
|
273
242
|
array[c] = iValue;
|
|
@@ -321,7 +290,7 @@ export class MinHeap {
|
|
|
321
290
|
const last = heapArray.length - 1;
|
|
322
291
|
if (index !== last) {
|
|
323
292
|
const item = heapArray[index],
|
|
324
|
-
newItem = heapArray[index] = heapArray.pop();
|
|
293
|
+
newItem = (heapArray[index] = heapArray.pop());
|
|
325
294
|
return MinHeap.updateByIndex(heapArray, index, less(newItem, item), less);
|
|
326
295
|
}
|
|
327
296
|
heapArray.pop();
|
|
@@ -360,6 +329,6 @@ export class MinHeap {
|
|
|
360
329
|
}
|
|
361
330
|
}
|
|
362
331
|
|
|
363
|
-
MinHeap.defaults = {less: defaultLess, equal: defaultEqual};
|
|
332
|
+
MinHeap.defaults = {less: defaultLess, equal: defaultEqual, compare: null};
|
|
364
333
|
|
|
365
334
|
export default MinHeap;
|
package/src/list/nodes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import {isRangeLike, normalizeNode, normalizeRange} from '../list-helpers.js';
|
|
4
|
-
import {addAlias, copyDescriptors} from '../meta-utils.js';
|
|
4
|
+
import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
|
|
5
5
|
|
|
6
6
|
export const isNodeLike = ({nextName, prevName}, node) => node && node[prevName] && node[nextName];
|
|
7
7
|
export const isStandAlone = ({nextName, prevName}, node) => node && node[prevName] === node && node[nextName] === node;
|
|
@@ -22,9 +22,9 @@ export class HeadNode extends Node {
|
|
|
22
22
|
isNodeLike(node) {
|
|
23
23
|
if (!node) return false;
|
|
24
24
|
const next = node[this.nextName];
|
|
25
|
-
if (!next || typeof next
|
|
25
|
+
if (!next || canHaveProps[typeof next] !== 1) return false;
|
|
26
26
|
const prev = node[this.prevName];
|
|
27
|
-
return prev && typeof prev
|
|
27
|
+
return prev && canHaveProps[typeof prev] === 1;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
isCompatibleNames({nextName, prevName}) {
|
package/src/meta-utils.js
CHANGED
|
@@ -100,7 +100,7 @@ export const addAlias = (object, name, aliases, force) => addDescriptor(object,
|
|
|
100
100
|
export const addAliases = (object, dict, force) => copyDescriptors(object, object, dict, force);
|
|
101
101
|
|
|
102
102
|
export const augmentIterator = iterator => {
|
|
103
|
-
if (!
|
|
103
|
+
if (!iterator.hasOwnProperty(Symbol.iterator)) {
|
|
104
104
|
iterator[Symbol.iterator] = function () {
|
|
105
105
|
return this;
|
|
106
106
|
};
|
|
@@ -131,6 +131,8 @@ export const mapIterator = (iterator, callbackFn) => {
|
|
|
131
131
|
};
|
|
132
132
|
};
|
|
133
133
|
|
|
134
|
+
export const canHaveProps = {object: 1, function: 1};
|
|
135
|
+
|
|
134
136
|
export const copyOptions = (target, pattern, ...sources) => {
|
|
135
137
|
target = target || {};
|
|
136
138
|
const keys = Object.keys(pattern);
|
|
@@ -138,7 +140,7 @@ export const copyOptions = (target, pattern, ...sources) => {
|
|
|
138
140
|
target[key] = pattern[key];
|
|
139
141
|
}
|
|
140
142
|
for (const source of sources) {
|
|
141
|
-
if (!source || typeof source !==
|
|
143
|
+
if (!source || canHaveProps[typeof source] !== 1) continue;
|
|
142
144
|
for (const key of keys) {
|
|
143
145
|
if (key in source) target[key] = source[key];
|
|
144
146
|
}
|
package/src/slist/nodes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
import {isRangeLike, normalizeNode, normalizeRange, normalizePtrRange} from '../list-helpers.js';
|
|
4
|
-
import {addAlias, copyDescriptors} from '../meta-utils.js';
|
|
4
|
+
import {addAlias, copyDescriptors, canHaveProps} from '../meta-utils.js';
|
|
5
5
|
|
|
6
6
|
export const isNodeLike = ({nextName}, node) => node && node[nextName];
|
|
7
7
|
export const isStandAlone = ({nextName}, node) => node && node[nextName] === node;
|
|
@@ -25,7 +25,7 @@ export class HeadNode extends Node {
|
|
|
25
25
|
isNodeLike(node) {
|
|
26
26
|
if (!node) return false;
|
|
27
27
|
const next = node[this.nextName];
|
|
28
|
-
return next && typeof next
|
|
28
|
+
return next && canHaveProps[typeof next] === 1;
|
|
29
29
|
}
|
|
30
30
|
isCompatibleNames({nextName}) {
|
|
31
31
|
return this.nextName === nextName;
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import {copyOptions} from '../meta-utils.js';
|
|
4
|
+
|
|
5
|
+
const defaultLess = (a, b) => a < b;
|
|
6
|
+
|
|
7
|
+
const zig = tree => {
|
|
8
|
+
const newTree = tree.left,
|
|
9
|
+
parent = (newTree.parent = tree.parent);
|
|
10
|
+
if (parent) {
|
|
11
|
+
if (parent.left === tree) parent.left = newTree;
|
|
12
|
+
else parent.right = newTree;
|
|
13
|
+
}
|
|
14
|
+
tree.parent = newTree;
|
|
15
|
+
const child = (tree.left = newTree.right);
|
|
16
|
+
if (child) child.parent = tree;
|
|
17
|
+
newTree.right = tree;
|
|
18
|
+
return newTree;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const zag = tree => {
|
|
22
|
+
const newTree = tree.right,
|
|
23
|
+
parent = (newTree.parent = tree.parent);
|
|
24
|
+
if (parent) {
|
|
25
|
+
if (parent.left === tree) parent.left = newTree;
|
|
26
|
+
else parent.right = newTree;
|
|
27
|
+
}
|
|
28
|
+
tree.parent = newTree;
|
|
29
|
+
const child = (tree.right = newTree.left);
|
|
30
|
+
if (child) child.parent = tree;
|
|
31
|
+
newTree.left = tree;
|
|
32
|
+
return newTree;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const splay = node => {
|
|
36
|
+
while (node.parent) {
|
|
37
|
+
if (!node.parent.parent) {
|
|
38
|
+
node.parent.left === node ? zig(node.parent) : zag(node.parent);
|
|
39
|
+
} else if (node.parent.left === node && node.parent.parent.left === node.parent) {
|
|
40
|
+
zig(node.parent.parent);
|
|
41
|
+
zig(node.parent);
|
|
42
|
+
} else if (node.parent.right === node && node.parent.parent.right === node.parent) {
|
|
43
|
+
zag(node.parent.parent);
|
|
44
|
+
zag(node.parent);
|
|
45
|
+
} else if (node.parent.left === node && node.parent.parent.right === node.parent) {
|
|
46
|
+
zig(node.parent);
|
|
47
|
+
zag(node.parent);
|
|
48
|
+
} else {
|
|
49
|
+
zag(node.parent);
|
|
50
|
+
zig(node.parent);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return node;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const count = tree => (tree ? count(tree.left) + count(tree.right) + 1 : 0);
|
|
57
|
+
|
|
58
|
+
export class SplayTreeNode {
|
|
59
|
+
constructor(value) {
|
|
60
|
+
this.left = this.right = this.parent = null;
|
|
61
|
+
this.value = value;
|
|
62
|
+
}
|
|
63
|
+
getMin() {
|
|
64
|
+
let z = this;
|
|
65
|
+
while (z.left) z = z.left;
|
|
66
|
+
return z;
|
|
67
|
+
}
|
|
68
|
+
getMax() {
|
|
69
|
+
let z = this;
|
|
70
|
+
while (z.right) z = z.right;
|
|
71
|
+
return z;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class SplayTree {
|
|
76
|
+
constructor(options) {
|
|
77
|
+
copyOptions(this, SplayTree.defaults, options);
|
|
78
|
+
if (typeof this.compare == 'function') {
|
|
79
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
80
|
+
this.find = this.findWithCompare;
|
|
81
|
+
this.insert = this.insertWithCompare;
|
|
82
|
+
this.splitMaxTree = this.splitMaxTreeWithCompare;
|
|
83
|
+
}
|
|
84
|
+
this.root = null;
|
|
85
|
+
this.size = 0;
|
|
86
|
+
}
|
|
87
|
+
get isEmpty() {
|
|
88
|
+
return !this.root;
|
|
89
|
+
}
|
|
90
|
+
get length() {
|
|
91
|
+
return this.size;
|
|
92
|
+
}
|
|
93
|
+
getMin() {
|
|
94
|
+
return this.root.getMin();
|
|
95
|
+
}
|
|
96
|
+
getMax() {
|
|
97
|
+
return this.root.getMax();
|
|
98
|
+
}
|
|
99
|
+
find(value) {
|
|
100
|
+
for (let z = this.root; z; ) {
|
|
101
|
+
if (this.less(z.value, value)) z = z.right;
|
|
102
|
+
else if (this.less(value, z.value)) z = z.left;
|
|
103
|
+
else return z;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
findWithCompare(value) {
|
|
108
|
+
for (let z = this.root; z; ) {
|
|
109
|
+
const cmp = this.compare(value, z.value);
|
|
110
|
+
if (cmp < 0) z = z.left;
|
|
111
|
+
else if (cmp > 0) z = z.right;
|
|
112
|
+
else return z;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
promote(value) {
|
|
117
|
+
const z = this.find(value);
|
|
118
|
+
if (z) {
|
|
119
|
+
this.root = splay(z);
|
|
120
|
+
}
|
|
121
|
+
return z;
|
|
122
|
+
}
|
|
123
|
+
splay(node) {
|
|
124
|
+
this.root = splay(node);
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
insert(value) {
|
|
128
|
+
let z = this.root,
|
|
129
|
+
parent = null;
|
|
130
|
+
while (z) {
|
|
131
|
+
parent = z;
|
|
132
|
+
if (this.less(z.value, value)) z = z.right;
|
|
133
|
+
else if (this.less(value, z.value)) z = z.left;
|
|
134
|
+
else break;
|
|
135
|
+
}
|
|
136
|
+
if (!z) {
|
|
137
|
+
z = new SplayTreeNode(value);
|
|
138
|
+
z.parent = parent;
|
|
139
|
+
if (parent) {
|
|
140
|
+
if (this.less(parent.value, value)) parent.right = z;
|
|
141
|
+
else parent.left = z;
|
|
142
|
+
}
|
|
143
|
+
++this.size;
|
|
144
|
+
}
|
|
145
|
+
this.root = splay(z);
|
|
146
|
+
return this;
|
|
147
|
+
}
|
|
148
|
+
insertWithCompare(value) {
|
|
149
|
+
let z = this.root,
|
|
150
|
+
parent = null;
|
|
151
|
+
while (z) {
|
|
152
|
+
parent = z;
|
|
153
|
+
const cmp = this.compare(value, z.value);
|
|
154
|
+
if (cmp < 0) z = z.left;
|
|
155
|
+
else if (cmp > 0) z = z.right;
|
|
156
|
+
else break;
|
|
157
|
+
}
|
|
158
|
+
if (!z) {
|
|
159
|
+
z = new SplayTreeNode(value);
|
|
160
|
+
z.parent = parent;
|
|
161
|
+
if (parent) {
|
|
162
|
+
if (this.compare(parent.value, value) < 0) parent.right = z;
|
|
163
|
+
else parent.left = z;
|
|
164
|
+
}
|
|
165
|
+
++this.size;
|
|
166
|
+
}
|
|
167
|
+
this.root = splay(z);
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
remove(value) {
|
|
171
|
+
const z = this.find(value);
|
|
172
|
+
if (!z) return this;
|
|
173
|
+
|
|
174
|
+
splay(z);
|
|
175
|
+
this.root = null;
|
|
176
|
+
|
|
177
|
+
let maxNode = null;
|
|
178
|
+
if (z.left) {
|
|
179
|
+
z.left.parent = null;
|
|
180
|
+
maxNode = z.left.getMax();
|
|
181
|
+
this.root = splay(maxNode);
|
|
182
|
+
}
|
|
183
|
+
if (z.right) {
|
|
184
|
+
if (maxNode) maxNode.right = z.right;
|
|
185
|
+
else this.root = z.right;
|
|
186
|
+
z.right.parent = maxNode;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
--this.size;
|
|
190
|
+
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
clear() {
|
|
194
|
+
this.root = null;
|
|
195
|
+
this.size = 0;
|
|
196
|
+
return this;
|
|
197
|
+
}
|
|
198
|
+
splitMaxTree(value) {
|
|
199
|
+
if (!this.root) return new SplayTree(this);
|
|
200
|
+
let z = this.root,
|
|
201
|
+
parent = null,
|
|
202
|
+
right;
|
|
203
|
+
while (z) {
|
|
204
|
+
parent = z;
|
|
205
|
+
if (this.less(z.value, value)) {
|
|
206
|
+
z = z.right;
|
|
207
|
+
right = true;
|
|
208
|
+
} else if (this.less(value, z.value)) {
|
|
209
|
+
z = z.left;
|
|
210
|
+
right = false;
|
|
211
|
+
} else break;
|
|
212
|
+
}
|
|
213
|
+
this.root = splay(z || parent);
|
|
214
|
+
|
|
215
|
+
const newTree = new SplayTree(this);
|
|
216
|
+
if (z || right) {
|
|
217
|
+
newTree.root = this.root.right;
|
|
218
|
+
if (newTree.root) {
|
|
219
|
+
newTree.root.parent = null;
|
|
220
|
+
newTree.size = count(newTree.root);
|
|
221
|
+
this.root.right = null;
|
|
222
|
+
this.size -= newTree.size;
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
newTree.root = this.root;
|
|
226
|
+
newTree.size = this.size;
|
|
227
|
+
this.root = this.root.left;
|
|
228
|
+
if (this.root) {
|
|
229
|
+
this.root.parent = null;
|
|
230
|
+
this.size = count(this.root);
|
|
231
|
+
newTree.root.left = null;
|
|
232
|
+
newTree.size -= this.size;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return newTree;
|
|
236
|
+
}
|
|
237
|
+
splitMaxTreeWithCompare(value) {
|
|
238
|
+
if (!this.root) return new SplayTree(this);
|
|
239
|
+
let z = this.root,
|
|
240
|
+
parent = null,
|
|
241
|
+
right;
|
|
242
|
+
while (z) {
|
|
243
|
+
parent = z;
|
|
244
|
+
const cmp = this.compare(value, z.value);
|
|
245
|
+
if (cmp < 0) {
|
|
246
|
+
z = z.left;
|
|
247
|
+
right = false;
|
|
248
|
+
} else if (cmp > 0) {
|
|
249
|
+
z = z.right;
|
|
250
|
+
right = true;
|
|
251
|
+
} else break;
|
|
252
|
+
}
|
|
253
|
+
this.root = splay(z || parent);
|
|
254
|
+
|
|
255
|
+
const newTree = new SplayTree(this);
|
|
256
|
+
if (z || right) {
|
|
257
|
+
newTree.root = this.root.right;
|
|
258
|
+
if (newTree.root) {
|
|
259
|
+
newTree.root.parent = null;
|
|
260
|
+
newTree.size = count(newTree.root);
|
|
261
|
+
this.root.right = null;
|
|
262
|
+
this.size -= newTree.size;
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
newTree.root = this.root;
|
|
266
|
+
newTree.size = this.size;
|
|
267
|
+
this.root = this.root.left;
|
|
268
|
+
if (this.root) {
|
|
269
|
+
this.root.parent = null;
|
|
270
|
+
this.size = count(this.root);
|
|
271
|
+
newTree.root.left = null;
|
|
272
|
+
newTree.size -= this.size;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return newTree;
|
|
276
|
+
}
|
|
277
|
+
joinMaxTreeUnsafe(tree) {
|
|
278
|
+
if (this.root.right) {
|
|
279
|
+
this.splay(this.getMax());
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
this.root.right = tree.root;
|
|
283
|
+
tree.root.parent = this.root;
|
|
284
|
+
this.size += tree.size;
|
|
285
|
+
|
|
286
|
+
tree.clear();
|
|
287
|
+
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
join(tree) {
|
|
291
|
+
if (!tree.root) return this;
|
|
292
|
+
if (!this.root) {
|
|
293
|
+
this.root = tree.root;
|
|
294
|
+
this.size = tree.size;
|
|
295
|
+
tree.clear();
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const leftMax = this.getMax(), rightMin = tree.getMin();
|
|
300
|
+
if (this.less(leftMax.value, rightMin.value)) {
|
|
301
|
+
return this.splay(leftMax).joinMaxTreeUnsafe(tree);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
for (const value of tree) {
|
|
305
|
+
this.insert(value);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
tree.clear();
|
|
309
|
+
return this;
|
|
310
|
+
}
|
|
311
|
+
[Symbol.iterator]() {
|
|
312
|
+
let current = this.root ? this.root.getMin() : null;
|
|
313
|
+
return {
|
|
314
|
+
next: () => {
|
|
315
|
+
if (!current) return {done: true};
|
|
316
|
+
const last = current;
|
|
317
|
+
if (current.right) {
|
|
318
|
+
current = current.right.getMin();
|
|
319
|
+
} else {
|
|
320
|
+
for (;;) {
|
|
321
|
+
const parent = current.parent;
|
|
322
|
+
if (!parent) {
|
|
323
|
+
current = null;
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
if (parent.left === current) {
|
|
327
|
+
current = parent;
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
current = parent;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {value: last.value};
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
getReverseIterator() {
|
|
338
|
+
return {
|
|
339
|
+
[Symbol.iterator]: () => {
|
|
340
|
+
let current = this.root ? this.root.getMax() : null;
|
|
341
|
+
return {
|
|
342
|
+
next: () => {
|
|
343
|
+
if (!current) return {done: true};
|
|
344
|
+
const last = current;
|
|
345
|
+
if (current.left) {
|
|
346
|
+
current = current.left.getMax();
|
|
347
|
+
} else {
|
|
348
|
+
for (;;) {
|
|
349
|
+
const parent = current.parent;
|
|
350
|
+
if (!parent) {
|
|
351
|
+
current = null;
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
if (parent.right === current) {
|
|
355
|
+
current = parent;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
current = parent;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return {value: last.value};
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
static from(values, options) {
|
|
368
|
+
const tree = new SplayTree(options);
|
|
369
|
+
for (const value of values) {
|
|
370
|
+
tree.insert(value);
|
|
371
|
+
}
|
|
372
|
+
return tree;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
SplayTree.defaults = {less: defaultLess, compare: null};
|
|
377
|
+
|
|
378
|
+
export default SplayTree;
|