list-toolkit 1.0.2 → 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 +89 -419
- package/cjs/cache/cache-fifo.js +37 -0
- package/cjs/cache/cache-lfu.js +76 -0
- package/cjs/cache/cache-lru.js +100 -0
- package/cjs/cache/cache-random.js +77 -0
- package/cjs/cache/decorator.js +47 -0
- package/cjs/cache.js +28 -0
- package/cjs/ext-list.js +22 -0
- package/cjs/ext-slist.js +22 -0
- package/cjs/ext-value-list.js +22 -0
- package/cjs/ext-value-slist.js +22 -0
- package/cjs/{MinHeap.js → heap/min-heap.js} +68 -82
- package/cjs/heap.js +22 -0
- package/cjs/list/basics.js +88 -0
- package/cjs/list/core.js +305 -0
- package/cjs/list/ext-value.js +89 -0
- package/cjs/list/ext.js +356 -0
- package/cjs/list/nodes.js +240 -0
- package/cjs/list/ptr.js +61 -0
- package/cjs/list/value.js +100 -0
- package/cjs/list-helpers.js +91 -0
- package/cjs/list-utils.js +141 -0
- package/cjs/list.js +22 -0
- package/cjs/meta-utils.js +167 -0
- package/cjs/nt-utils.js +132 -0
- package/cjs/queue.js +58 -0
- package/cjs/slist/basics.js +71 -0
- package/cjs/slist/core.js +362 -0
- package/cjs/slist/ext-value.js +83 -0
- package/cjs/slist/ext.js +336 -0
- package/cjs/slist/nodes.js +276 -0
- package/cjs/slist/ptr.js +87 -0
- package/cjs/slist/value.js +91 -0
- package/cjs/slist.js +22 -0
- package/cjs/stack.js +55 -0
- package/cjs/tree/splay-tree.js +362 -0
- package/cjs/value-list.js +22 -0
- package/cjs/value-slist.js +22 -0
- package/package.json +7 -7
- package/src/cache/cache-fifo.js +27 -0
- package/src/cache/cache-lfu.js +63 -0
- package/src/cache/cache-lru.js +87 -0
- package/src/cache/cache-random.js +73 -0
- package/src/cache/decorator.js +45 -0
- package/src/cache.js +9 -0
- package/src/ext-list.js +6 -0
- package/src/ext-slist.js +6 -0
- package/src/ext-value-list.js +6 -0
- package/src/ext-value-slist.js +6 -0
- package/src/{MinHeap.js → heap/min-heap.js} +73 -85
- package/src/heap.js +6 -0
- package/src/list/basics.js +64 -0
- package/src/list/core.js +314 -0
- package/src/list/ext-value.js +81 -0
- package/src/list/ext.js +370 -0
- package/src/list/nodes.js +262 -0
- package/src/list/ptr.js +58 -0
- package/src/list/value.js +88 -0
- package/src/list-helpers.js +80 -0
- package/src/list-utils.js +140 -0
- package/src/list.js +6 -0
- package/src/meta-utils.js +147 -0
- package/src/nt-utils.js +85 -0
- package/src/queue.js +52 -0
- package/src/slist/basics.js +47 -0
- package/src/slist/core.js +364 -0
- package/src/slist/ext-value.js +74 -0
- package/src/slist/ext.js +331 -0
- package/src/slist/nodes.js +290 -0
- package/src/slist/ptr.js +77 -0
- package/src/slist/value.js +75 -0
- package/src/slist.js +6 -0
- package/src/stack.js +52 -0
- package/src/tree/splay-tree.js +378 -0
- package/src/value-list.js +6 -0
- package/src/value-slist.js +6 -0
- package/cjs/Cache.js +0 -71
- package/cjs/List.js +0 -294
- package/cjs/ListHead.js +0 -309
- package/cjs/SList.js +0 -342
- package/cjs/SListHead.js +0 -367
- package/cjs/utils.js +0 -43
- package/src/Cache.js +0 -61
- package/src/List.js +0 -303
- package/src/ListHead.js +0 -304
- package/src/SList.js +0 -330
- package/src/SListHead.js +0 -354
- package/src/utils.js +0 -35
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import ValueList from '../value-list.js';
|
|
4
|
+
import {addAliases} from '../meta-utils.js';
|
|
5
|
+
|
|
6
|
+
// The base cache class. Evicts the least recently used items.
|
|
7
|
+
// Based on doubly linked value lists.
|
|
8
|
+
|
|
9
|
+
export class CacheLRU {
|
|
10
|
+
constructor(capacity = 10) {
|
|
11
|
+
this.capacity = capacity;
|
|
12
|
+
this.list = new ValueList();
|
|
13
|
+
this.dict = new Map();
|
|
14
|
+
}
|
|
15
|
+
get isEmpty() {
|
|
16
|
+
return !this.dict.size;
|
|
17
|
+
}
|
|
18
|
+
get size() {
|
|
19
|
+
return this.dict.size;
|
|
20
|
+
}
|
|
21
|
+
has(key) {
|
|
22
|
+
return this.dict.has(key);
|
|
23
|
+
}
|
|
24
|
+
find(key) {
|
|
25
|
+
const node = this.use(key);
|
|
26
|
+
return node ? node.value.value : undefined;
|
|
27
|
+
}
|
|
28
|
+
remove(key) {
|
|
29
|
+
const node = this.dict.get(key);
|
|
30
|
+
if (node) {
|
|
31
|
+
this.dict.delete(key);
|
|
32
|
+
this.list.removeNode(node);
|
|
33
|
+
}
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
register(key, value) {
|
|
37
|
+
const node = this.use(key);
|
|
38
|
+
if (node) {
|
|
39
|
+
this.update(node, value);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
if (this.dict.size >= this.capacity) {
|
|
43
|
+
this.evictAndReplace(key, value);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
this.addNew(key, value);
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
use(key) {
|
|
50
|
+
const node = this.dict.get(key);
|
|
51
|
+
if (node) this.list.moveToFront(node);
|
|
52
|
+
return node;
|
|
53
|
+
}
|
|
54
|
+
update(node, value) {
|
|
55
|
+
node.value.value = value;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
addNew(key, value) {
|
|
59
|
+
this.list.pushFront({key, value});
|
|
60
|
+
const node = this.list.front;
|
|
61
|
+
this.dict.set(key, node);
|
|
62
|
+
return node;
|
|
63
|
+
}
|
|
64
|
+
evictAndReplace(key, value) {
|
|
65
|
+
const node = this.list.back;
|
|
66
|
+
this.list.moveToFront(node);
|
|
67
|
+
this.dict.delete(node.value.key);
|
|
68
|
+
this.dict.set(key, node);
|
|
69
|
+
node.value = {key, value};
|
|
70
|
+
return node;
|
|
71
|
+
}
|
|
72
|
+
clear() {
|
|
73
|
+
this.dict.clear();
|
|
74
|
+
this.list.clear();
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
[Symbol.iterator]() {
|
|
78
|
+
return this.list[Symbol.iterator]();
|
|
79
|
+
}
|
|
80
|
+
getReverseIterator() {
|
|
81
|
+
return this.list.getReverseIterator();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
addAliases(CacheLRU.prototype, {register: 'add, set', remove: 'delete', find: 'get'});
|
|
86
|
+
|
|
87
|
+
export default CacheLRU;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import {addAlias} from '../meta-utils.js';
|
|
4
|
+
import MinHeap from '../heap/min-heap.js';
|
|
5
|
+
import CacheLRU from './cache-lru.js';
|
|
6
|
+
|
|
7
|
+
// Evicts items randomly.
|
|
8
|
+
|
|
9
|
+
export class CacheRandom extends CacheLRU {
|
|
10
|
+
constructor(capacity = 10) {
|
|
11
|
+
super(capacity);
|
|
12
|
+
this.heap = new MinHeap({less: (a, b) => a.value.id > b.value.id});
|
|
13
|
+
this.nextId = 0;
|
|
14
|
+
}
|
|
15
|
+
use(key) {
|
|
16
|
+
return this.dict.get(key);
|
|
17
|
+
}
|
|
18
|
+
update(node, value) {
|
|
19
|
+
node.value.value = value;
|
|
20
|
+
return this;
|
|
21
|
+
}
|
|
22
|
+
addNew(key, value) {
|
|
23
|
+
this.list.pushFront({key, value, id: this.nextId++});
|
|
24
|
+
const node = this.list.front;
|
|
25
|
+
this.dict.set(key, node);
|
|
26
|
+
this.heap.push(node);
|
|
27
|
+
return node;
|
|
28
|
+
}
|
|
29
|
+
evictAndReplace(key, value) {
|
|
30
|
+
const index = Math.floor(this.heap.length * Math.random());
|
|
31
|
+
|
|
32
|
+
const node = this.heap.array[index],
|
|
33
|
+
isDecreased = value > node.value.value;
|
|
34
|
+
|
|
35
|
+
this.dict.delete(node.value.key);
|
|
36
|
+
this.dict.set(key, node);
|
|
37
|
+
|
|
38
|
+
node.value.key = key;
|
|
39
|
+
node.value.value = value;
|
|
40
|
+
|
|
41
|
+
this.heap.updateByIndex(index, isDecreased);
|
|
42
|
+
|
|
43
|
+
return node;
|
|
44
|
+
}
|
|
45
|
+
remove(key) {
|
|
46
|
+
const node = this.dict.get(key);
|
|
47
|
+
if (node) {
|
|
48
|
+
this.dict.delete(key);
|
|
49
|
+
this.list.removeNode(node);
|
|
50
|
+
this.heap.remove(node);
|
|
51
|
+
}
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
clear() {
|
|
55
|
+
super.clear();
|
|
56
|
+
this.heap.clear();
|
|
57
|
+
this.nextId = 0;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
resetIds() {
|
|
61
|
+
this.nextId = 0;
|
|
62
|
+
for (const item of this.heap) {
|
|
63
|
+
item.id = this.nextId++;
|
|
64
|
+
}
|
|
65
|
+
const array = this.heap.array;
|
|
66
|
+
this.heap.clear().merge(array);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
addAlias(CacheRandom.prototype, 'remove', 'delete');
|
|
72
|
+
|
|
73
|
+
export default CacheRandom;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export const decorateFn = (fn, cache) => {
|
|
4
|
+
if (typeof fn !== 'function') throw new TypeError('Not a function');
|
|
5
|
+
const wrapped = function (...args) {
|
|
6
|
+
const key = args[0],
|
|
7
|
+
cache = wrapped.cache;
|
|
8
|
+
if (cache.has(key)) return cache.get(key);
|
|
9
|
+
const result = wrapped.fn.apply(this, args);
|
|
10
|
+
cache.set(key, result);
|
|
11
|
+
return result;
|
|
12
|
+
};
|
|
13
|
+
wrapped.fn = fn;
|
|
14
|
+
wrapped.cache = cache;
|
|
15
|
+
return wrapped;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const decorate = (object, key, cache) => {
|
|
19
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
20
|
+
if (!descriptor) throw new Error('Missing property: ' + key);
|
|
21
|
+
|
|
22
|
+
const newDescriptor = {...descriptor},
|
|
23
|
+
wrapped = decorateFn(descriptor.value, cache);
|
|
24
|
+
|
|
25
|
+
newDescriptor.value = wrapped;
|
|
26
|
+
|
|
27
|
+
Object.defineProperty(object, key, newDescriptor);
|
|
28
|
+
|
|
29
|
+
return wrapped;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const decorateMethod = (object, key, cache) => {
|
|
33
|
+
const fn = object[key],
|
|
34
|
+
wrapped = decorateFn(fn, cache);
|
|
35
|
+
object[key] = wrapped;
|
|
36
|
+
return wrapped;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const getCache = (object, key) => {
|
|
40
|
+
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
41
|
+
if (!descriptor) throw new Error('Missing property: ' + key);
|
|
42
|
+
return descriptor.value.cache;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default decorate;
|
package/src/cache.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
export * from './cache/cache-lru.js';
|
|
4
|
+
import Cache from './cache/cache-lru.js';
|
|
5
|
+
import decorator from './cache/decorator.js';
|
|
6
|
+
|
|
7
|
+
export const cacheDecorator = (object, key, cache = new Cache()) => decorator(object, key, cache);
|
|
8
|
+
|
|
9
|
+
export default Cache;
|
package/src/ext-list.js
ADDED
package/src/ext-slist.js
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
import {copyOptions} from '
|
|
3
|
+
import {copyOptions} from '../meta-utils.js';
|
|
4
4
|
|
|
5
5
|
// the following functions are inlined:
|
|
6
6
|
|
|
@@ -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
|
}
|
|
@@ -64,9 +61,8 @@ export class MinHeap {
|
|
|
64
61
|
return this.array[0];
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
|
|
68
|
-
this.array
|
|
69
|
-
return this;
|
|
64
|
+
peek() {
|
|
65
|
+
return this.array[0];
|
|
70
66
|
}
|
|
71
67
|
|
|
72
68
|
pop() {
|
|
@@ -84,17 +80,10 @@ export class MinHeap {
|
|
|
84
80
|
for (let i = 0; ; ) {
|
|
85
81
|
const l = (i << 1) + 1;
|
|
86
82
|
if (l >= n) break;
|
|
87
|
-
|
|
83
|
+
const r = l + 1,
|
|
84
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
85
|
+
iValue = this.array[i],
|
|
88
86
|
cValue = this.array[c];
|
|
89
|
-
const r = c + 1;
|
|
90
|
-
if (r < n) {
|
|
91
|
-
const rValue = this.array[r];
|
|
92
|
-
if (this.less(rValue, cValue)) {
|
|
93
|
-
c = r;
|
|
94
|
-
cValue = rValue;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const iValue = this.array[i];
|
|
98
87
|
if (!this.less(cValue, iValue)) break;
|
|
99
88
|
this.array[i] = cValue;
|
|
100
89
|
this.array[c] = iValue;
|
|
@@ -128,17 +117,10 @@ export class MinHeap {
|
|
|
128
117
|
for (let i = 0; ; ) {
|
|
129
118
|
const l = (i << 1) + 1;
|
|
130
119
|
if (l >= n) break;
|
|
131
|
-
|
|
120
|
+
const r = l + 1,
|
|
121
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
122
|
+
iValue = this.array[i],
|
|
132
123
|
cValue = this.array[c];
|
|
133
|
-
const r = c + 1;
|
|
134
|
-
if (r < n) {
|
|
135
|
-
const rValue = this.array[r];
|
|
136
|
-
if (this.less(rValue, cValue)) {
|
|
137
|
-
c = r;
|
|
138
|
-
cValue = rValue;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
const iValue = this.array[i];
|
|
142
124
|
if (!this.less(cValue, iValue)) break;
|
|
143
125
|
this.array[i] = cValue;
|
|
144
126
|
this.array[c] = iValue;
|
|
@@ -156,17 +138,10 @@ export class MinHeap {
|
|
|
156
138
|
for (let i = 0; ; ) {
|
|
157
139
|
const l = (i << 1) + 1;
|
|
158
140
|
if (l >= n) break;
|
|
159
|
-
|
|
141
|
+
const r = l + 1,
|
|
142
|
+
c = r < n && this.less(this.array[r], this.array[l]) ? r : l,
|
|
143
|
+
iValue = this.array[i],
|
|
160
144
|
cValue = this.array[c];
|
|
161
|
-
const r = c + 1;
|
|
162
|
-
if (r < n) {
|
|
163
|
-
const rValue = this.array[r];
|
|
164
|
-
if (this.less(rValue, cValue)) {
|
|
165
|
-
c = r;
|
|
166
|
-
cValue = rValue;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const iValue = this.array[i];
|
|
170
145
|
if (!this.less(cValue, iValue)) break;
|
|
171
146
|
this.array[i] = cValue;
|
|
172
147
|
this.array[c] = iValue;
|
|
@@ -180,12 +155,43 @@ export class MinHeap {
|
|
|
180
155
|
return this.array.findIndex(element => this.equal(element, value)) >= 0;
|
|
181
156
|
}
|
|
182
157
|
|
|
158
|
+
findIndex(value) {
|
|
159
|
+
return this.array.findIndex(element => this.equal(element, value));
|
|
160
|
+
}
|
|
161
|
+
|
|
183
162
|
remove(value) {
|
|
184
|
-
|
|
163
|
+
MinHeap.remove(this.array, value, this.less, this.equal);
|
|
164
|
+
return this;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
removeByIndex(index) {
|
|
168
|
+
MinHeap.removeByIndex(this.array, index, this.less);
|
|
169
|
+
return this;
|
|
185
170
|
}
|
|
186
171
|
|
|
187
172
|
replace(value, newValue) {
|
|
188
|
-
|
|
173
|
+
MinHeap.replace(this.array, value, newValue, this.less, this.equal);
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
replaceByIndex(index, newValue) {
|
|
178
|
+
MinHeap.replaceByIndex(this.array, index, newValue, this.less);
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
updateTop() {
|
|
183
|
+
down(this.array, 0, this.less);
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
updateByIndex(index, isDecreased) {
|
|
188
|
+
MinHeap.updateByIndex(this.array, index, isDecreased, this.less);
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
clear() {
|
|
193
|
+
this.array = [];
|
|
194
|
+
return this;
|
|
189
195
|
}
|
|
190
196
|
|
|
191
197
|
releaseSorted() {
|
|
@@ -227,17 +233,10 @@ export class MinHeap {
|
|
|
227
233
|
for (let i = j; ; ) {
|
|
228
234
|
const l = (i << 1) + 1;
|
|
229
235
|
if (l >= n) break;
|
|
230
|
-
|
|
236
|
+
const r = l + 1,
|
|
237
|
+
c = r < n && less(array[r], array[l]) ? r : l,
|
|
238
|
+
iValue = array[i],
|
|
231
239
|
cValue = array[c];
|
|
232
|
-
const r = c + 1;
|
|
233
|
-
if (r < n) {
|
|
234
|
-
const rValue = array[r];
|
|
235
|
-
if (less(rValue, cValue)) {
|
|
236
|
-
c = r;
|
|
237
|
-
cValue = rValue;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const iValue = array[i];
|
|
241
240
|
if (!less(cValue, iValue)) break;
|
|
242
241
|
array[i] = cValue;
|
|
243
242
|
array[c] = iValue;
|
|
@@ -268,10 +267,7 @@ export class MinHeap {
|
|
|
268
267
|
|
|
269
268
|
static pushPop(heapArray, item, less = MinHeap.defaults.less) {
|
|
270
269
|
if (!heapArray.length || less(item, heapArray[0])) return item;
|
|
271
|
-
|
|
272
|
-
heapArray[0] = item;
|
|
273
|
-
down(heapArray, 0, less);
|
|
274
|
-
return top;
|
|
270
|
+
return MinHeap.replaceTop(heapArray, item, less);
|
|
275
271
|
}
|
|
276
272
|
|
|
277
273
|
static replaceTop(heapArray, item, less = MinHeap.defaults.less) {
|
|
@@ -289,46 +285,38 @@ export class MinHeap {
|
|
|
289
285
|
return heapArray.findIndex(element => equal(element, item));
|
|
290
286
|
}
|
|
291
287
|
|
|
292
|
-
static removeByIndex(heapArray, index, less = MinHeap.defaults.less
|
|
288
|
+
static removeByIndex(heapArray, index, less = MinHeap.defaults.less) {
|
|
293
289
|
if (index < 0 || index >= heapArray.length) return this;
|
|
294
290
|
const last = heapArray.length - 1;
|
|
295
291
|
if (index !== last) {
|
|
296
|
-
const item = heapArray[index]
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
return
|
|
292
|
+
const item = heapArray[index],
|
|
293
|
+
newItem = (heapArray[index] = heapArray.pop());
|
|
294
|
+
return MinHeap.updateByIndex(heapArray, index, less(newItem, item), less);
|
|
295
|
+
}
|
|
296
|
+
heapArray.pop();
|
|
297
|
+
return heapArray;
|
|
302
298
|
}
|
|
303
299
|
|
|
304
300
|
static remove(heapArray, item, less = MinHeap.defaults.less, equal = MinHeap.defaults.equal) {
|
|
305
301
|
const index = heapArray.findIndex(element => equal(element, item));
|
|
306
|
-
|
|
307
|
-
const last = heapArray.length - 1;
|
|
308
|
-
if (index !== last) {
|
|
309
|
-
heapArray[index] = heapArray.pop();
|
|
310
|
-
if (less(heapArray[index], item)) up(heapArray, index, less);
|
|
311
|
-
else down(heapArray, index, less);
|
|
312
|
-
} else heapArray.pop();
|
|
313
|
-
return this;
|
|
302
|
+
return MinHeap.removeByIndex(heapArray, index, less);
|
|
314
303
|
}
|
|
315
304
|
|
|
316
|
-
static replaceByIndex(heapArray, index, newItem, less = MinHeap.defaults.less
|
|
305
|
+
static replaceByIndex(heapArray, index, newItem, less = MinHeap.defaults.less) {
|
|
317
306
|
if (index < 0 || index >= heapArray.length) return this;
|
|
318
307
|
const item = heapArray[index];
|
|
319
308
|
heapArray[index] = newItem;
|
|
320
|
-
|
|
321
|
-
else down(heapArray, index, less);
|
|
322
|
-
return this;
|
|
309
|
+
return MinHeap.updateByIndex(heapArray, index, less(newItem, item), less);
|
|
323
310
|
}
|
|
324
311
|
|
|
325
312
|
static replace(heapArray, item, newItem, less = MinHeap.defaults.less, equal = MinHeap.defaults.equal) {
|
|
326
313
|
const index = heapArray.findIndex(element => equal(element, item));
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return this;
|
|
314
|
+
return MinHeap.replaceByIndex(heapArray, index, newItem, less);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
static updateByIndex(heapArray, index, isDecreased, less = MinHeap.defaults.less) {
|
|
318
|
+
if (index < 0 || index >= heapArray.length) return this;
|
|
319
|
+
return (isDecreased ? up : down)(heapArray, index, less);
|
|
332
320
|
}
|
|
333
321
|
|
|
334
322
|
static sort(heapArray, less = MinHeap.defaults.less) {
|
|
@@ -341,6 +329,6 @@ export class MinHeap {
|
|
|
341
329
|
}
|
|
342
330
|
}
|
|
343
331
|
|
|
344
|
-
MinHeap.defaults = {less: defaultLess, equal: defaultEqual};
|
|
332
|
+
MinHeap.defaults = {less: defaultLess, equal: defaultEqual, compare: null};
|
|
345
333
|
|
|
346
334
|
export default MinHeap;
|
package/src/heap.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// useful low-level operations on doubly linked lists
|
|
4
|
+
|
|
5
|
+
export const extract = ({nextName, prevName}, {from, to = from}) => {
|
|
6
|
+
const next = to[nextName],
|
|
7
|
+
prev = from[prevName];
|
|
8
|
+
|
|
9
|
+
// extract
|
|
10
|
+
prev[nextName] = next;
|
|
11
|
+
next[prevName] = prev;
|
|
12
|
+
|
|
13
|
+
// clear
|
|
14
|
+
from[prevName] = to;
|
|
15
|
+
to[nextName] = from;
|
|
16
|
+
|
|
17
|
+
return {extracted: from, rest: next === from ? null : next};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// pop(options, head).node === extract(options, {from: node})
|
|
21
|
+
|
|
22
|
+
export const pop = ({nextName, prevName}, node) => {
|
|
23
|
+
const next = node[nextName],
|
|
24
|
+
prev = node[prevName];
|
|
25
|
+
|
|
26
|
+
// extract
|
|
27
|
+
prev[nextName] = next;
|
|
28
|
+
next[prevName] = prev;
|
|
29
|
+
|
|
30
|
+
// clear
|
|
31
|
+
node[prevName] = node[nextName] = node;
|
|
32
|
+
|
|
33
|
+
return {extracted: node, rest: next === node ? null : next};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const splice = ({nextName, prevName}, target, circularList) => {
|
|
37
|
+
const next = target[nextName],
|
|
38
|
+
from = circularList,
|
|
39
|
+
to = from[prevName];
|
|
40
|
+
|
|
41
|
+
// splice
|
|
42
|
+
target[nextName] = from;
|
|
43
|
+
from[prevName] = target;
|
|
44
|
+
to[nextName] = next;
|
|
45
|
+
next[prevName] = to;
|
|
46
|
+
|
|
47
|
+
return target;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// append(options, target, range) === splice(options, target, extract(options, range))
|
|
51
|
+
|
|
52
|
+
export const append = ({nextName, prevName}, target, {from, to = from}) => {
|
|
53
|
+
// extract
|
|
54
|
+
from[prevName][nextName] = to[nextName];
|
|
55
|
+
to[nextName][prevName] = from[prevName];
|
|
56
|
+
|
|
57
|
+
// splice
|
|
58
|
+
to[nextName] = target[nextName];
|
|
59
|
+
to[nextName][prevName] = to;
|
|
60
|
+
target[nextName] = from;
|
|
61
|
+
from[prevName] = target;
|
|
62
|
+
|
|
63
|
+
return target;
|
|
64
|
+
};
|