list-toolkit 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -102,7 +102,7 @@ const john = new Person('John'),
102
102
  const people = List.from([john, jane, jim, jill]);
103
103
 
104
104
  // iterator over the list manually:
105
- for (let node = people.front; node !== people; node = node[list.nextName]) {
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,7 @@ BSD 3-Clause "New" or "Revised" License. See the LICENSE file for details.
146
146
 
147
147
  ## Release History
148
148
 
149
+ * 2.1.0 *Added splay tree. Updated deps.*
149
150
  * 2.0.0 *New major release.*
150
151
  * 1.0.1 *Fixed exports. Added more methods to `MinHeap`.*
151
152
  * 1.0.1 *Initial release.*
@@ -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
- let c = l,
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
- let c = l,
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
- let c = l,
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
- let c = l,
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
- let c = l,
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/meta-utils.js CHANGED
@@ -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 (!Object.hasOwnProperty(Symbol.iterator)) {
122
+ if (!iterator.hasOwnProperty(Symbol.iterator)) {
123
123
  iterator[Symbol.iterator] = function () {
124
124
  return this;
125
125
  };
@@ -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.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "List-based data structures to organize your objects.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -33,10 +33,10 @@
33
33
  },
34
34
  "homepage": "https://github.com/uhop/list-toolkit#readme",
35
35
  "devDependencies": {
36
- "@babel/cli": "^7.24.7",
37
- "@babel/core": "^7.24.7",
38
- "@babel/preset-env": "^7.24.7",
39
- "tape-six": "^0.9.5"
36
+ "@babel/cli": "^7.24.8",
37
+ "@babel/core": "^7.25.2",
38
+ "@babel/preset-env": "^7.25.4",
39
+ "tape-six": "^0.9.6"
40
40
  },
41
41
  "files": [
42
42
  "/src",
@@ -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
- let c = l,
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
- let c = l,
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
- let c = l,
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
- let c = l,
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
- let c = l,
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/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 (!Object.hasOwnProperty(Symbol.iterator)) {
103
+ if (!iterator.hasOwnProperty(Symbol.iterator)) {
104
104
  iterator[Symbol.iterator] = function () {
105
105
  return this;
106
106
  };
@@ -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;