list-toolkit 2.1.1 → 2.2.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 +2 -1
- package/cjs/heap/basics.js +63 -0
- package/cjs/heap/leftist-heap.js +124 -0
- package/cjs/heap/min-heap.js +10 -14
- package/cjs/heap/skew-heap.js +114 -0
- package/package.json +3 -1
- package/src/heap/basics.js +58 -0
- package/src/heap/leftist-heap.js +125 -0
- package/src/heap/min-heap.js +10 -13
- package/src/heap/skew-heap.js +113 -0
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ The toolkit provides the following data structures with a full set of efficientl
|
|
|
15
15
|
* Value-based lists, where a list serves as a container for external objects, and node-based lists, where a list uses custom properties on external objects to link them around.
|
|
16
16
|
* Hosted lists, which use a special head node to manage nodes, and headless lists, which point to an external list without including any headers.
|
|
17
17
|
* Heaps:
|
|
18
|
-
*
|
|
18
|
+
* Priority queues: min heap, leftist heap, skew heap.
|
|
19
19
|
* Various list-based data structures:
|
|
20
20
|
* Caches with various eviction algorithms: least recently used (LRU), least frequently used (LFU), first in first out (FIFO), and random.
|
|
21
21
|
* A decorator is provided to decorate functions, methods, and getters with a cache of your choice.
|
|
@@ -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.2.0 *Added leftist and skew heaps.*
|
|
149
150
|
* 2.1.1 *Allowed functions to be used as nodes. Updated deps.*
|
|
150
151
|
* 2.1.0 *Added splay tree. Updated deps.*
|
|
151
152
|
* 2.0.0 *New major release.*
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.HeapBase = void 0;
|
|
7
|
+
var _metaUtils = require("../meta-utils.js");
|
|
8
|
+
const defaultLess = (a, b) => a < b;
|
|
9
|
+
const defaultEqual = (a, b) => a === b;
|
|
10
|
+
class HeapBase {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
(0, _metaUtils.copyOptions)(this, HeapBase.defaults, options);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// main methods
|
|
16
|
+
get isEmpty() {
|
|
17
|
+
throw new Error('Not implemented');
|
|
18
|
+
}
|
|
19
|
+
get top() {
|
|
20
|
+
throw new Error('Not implemented');
|
|
21
|
+
}
|
|
22
|
+
peek() {
|
|
23
|
+
return this.top;
|
|
24
|
+
}
|
|
25
|
+
pop() {
|
|
26
|
+
throw new Error('Not implemented');
|
|
27
|
+
}
|
|
28
|
+
push() {
|
|
29
|
+
throw new Error('Not implemented');
|
|
30
|
+
}
|
|
31
|
+
clear() {
|
|
32
|
+
throw new Error('Not implemented');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// performance methods
|
|
36
|
+
pushPop(value) {
|
|
37
|
+
this.push(value);
|
|
38
|
+
return this.pop();
|
|
39
|
+
}
|
|
40
|
+
replaceTop(value) {
|
|
41
|
+
const z = this.pop();
|
|
42
|
+
this.push(value);
|
|
43
|
+
return z;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// helper methods
|
|
47
|
+
merge(...args) {
|
|
48
|
+
throw new Error('Not implemented');
|
|
49
|
+
}
|
|
50
|
+
clone() {
|
|
51
|
+
throw new Error('Not implemented');
|
|
52
|
+
}
|
|
53
|
+
make(...args) {
|
|
54
|
+
return new this.constructor(this, ...args);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.HeapBase = HeapBase;
|
|
58
|
+
HeapBase.defaults = {
|
|
59
|
+
less: defaultLess,
|
|
60
|
+
equal: defaultEqual,
|
|
61
|
+
compare: null
|
|
62
|
+
};
|
|
63
|
+
var _default = exports.default = HeapBase;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.LeftistHeapNode = exports.LeftistHeap = void 0;
|
|
7
|
+
var _basics = _interopRequireDefault(require("./basics.js"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
const defaultLess = (a, b) => a < b;
|
|
10
|
+
const merge = (a, b, less) => {
|
|
11
|
+
if (!a) return b;
|
|
12
|
+
if (!b) return a;
|
|
13
|
+
if (less(b.value, a.value)) [a, b] = [b, a]; // swap
|
|
14
|
+
|
|
15
|
+
a.right = merge(a.right, b, less);
|
|
16
|
+
if (!a.left) {
|
|
17
|
+
[a.left, a.right] = [a.right, a.left]; // swap
|
|
18
|
+
a.s = 1;
|
|
19
|
+
return a;
|
|
20
|
+
}
|
|
21
|
+
if (a.left.s < a.right.s) {
|
|
22
|
+
[a.left, a.right] = [a.right, a.left]; // swap
|
|
23
|
+
}
|
|
24
|
+
a.s = a.right.s + 1;
|
|
25
|
+
return a;
|
|
26
|
+
};
|
|
27
|
+
class LeftistHeapNode {
|
|
28
|
+
constructor(value) {
|
|
29
|
+
this.value = value;
|
|
30
|
+
this.right = this.left = null;
|
|
31
|
+
this.s = 1;
|
|
32
|
+
}
|
|
33
|
+
clear() {
|
|
34
|
+
this.left = this.right = null;
|
|
35
|
+
this.s = 1;
|
|
36
|
+
}
|
|
37
|
+
clone() {
|
|
38
|
+
const node = new LeftistHeapNode(this.value);
|
|
39
|
+
node.left = this.left && this.left.clone();
|
|
40
|
+
node.right = this.right && this.right.clone();
|
|
41
|
+
return node;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.LeftistHeapNode = LeftistHeapNode;
|
|
45
|
+
class LeftistHeap extends _basics.default {
|
|
46
|
+
constructor(options, ...args) {
|
|
47
|
+
super(options);
|
|
48
|
+
if (typeof this.compare == 'function') {
|
|
49
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
50
|
+
}
|
|
51
|
+
this.root = null;
|
|
52
|
+
this.size = 0;
|
|
53
|
+
if (args.length) this.merge(...args);
|
|
54
|
+
}
|
|
55
|
+
get isEmpty() {
|
|
56
|
+
return !this.root;
|
|
57
|
+
}
|
|
58
|
+
get length() {
|
|
59
|
+
return this.size;
|
|
60
|
+
}
|
|
61
|
+
get top() {
|
|
62
|
+
return this.root ? this.root.value : undefined;
|
|
63
|
+
}
|
|
64
|
+
peek() {
|
|
65
|
+
return this.root ? this.root.value : undefined;
|
|
66
|
+
}
|
|
67
|
+
push(value) {
|
|
68
|
+
this.root = merge(this.root, new LeftistHeapNode(value), this.less);
|
|
69
|
+
++this.size;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
pop() {
|
|
73
|
+
if (!this.root) return;
|
|
74
|
+
const z = this.root;
|
|
75
|
+
this.root = merge(this.root.left, this.root.right, this.less);
|
|
76
|
+
--this.size;
|
|
77
|
+
return z.value;
|
|
78
|
+
}
|
|
79
|
+
pushPop(value) {
|
|
80
|
+
if (!this.root || this.less(value, this.root.value)) return value;
|
|
81
|
+
const z = this.root;
|
|
82
|
+
this.root = merge(z.left, new LeftistHeapNode(value), this.less);
|
|
83
|
+
this.root = merge(this.root, z.right, this.less);
|
|
84
|
+
return z.value;
|
|
85
|
+
}
|
|
86
|
+
replaceTop(value) {
|
|
87
|
+
if (!this.root) {
|
|
88
|
+
this.root = new LeftistHeapNode(value);
|
|
89
|
+
this.size = 1;
|
|
90
|
+
return; // undefined
|
|
91
|
+
}
|
|
92
|
+
const z = this.root;
|
|
93
|
+
this.root = merge(z.left, new LeftistHeapNode(value), this.less);
|
|
94
|
+
this.root = merge(this.root, z.right, this.less);
|
|
95
|
+
return z.value;
|
|
96
|
+
}
|
|
97
|
+
clear() {
|
|
98
|
+
this.root = null;
|
|
99
|
+
this.size = 0;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
merge(...args) {
|
|
103
|
+
for (const other of args) {
|
|
104
|
+
this.root = merge(this.root, other.root, this.less);
|
|
105
|
+
this.size += other.size;
|
|
106
|
+
other.root = null;
|
|
107
|
+
other.size = 0;
|
|
108
|
+
}
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
clone() {
|
|
112
|
+
const heap = new LeftistHeap(this);
|
|
113
|
+
heap.root = this.root && this.root.clone();
|
|
114
|
+
heap.size = this.size;
|
|
115
|
+
return heap;
|
|
116
|
+
}
|
|
117
|
+
static from(array, options = _basics.default.defaults) {
|
|
118
|
+
const heap = new LeftistHeap(options);
|
|
119
|
+
for (const value of array) heap.push(value);
|
|
120
|
+
return heap;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.LeftistHeap = LeftistHeap;
|
|
124
|
+
var _default = exports.default = LeftistHeap;
|
package/cjs/heap/min-heap.js
CHANGED
|
@@ -4,15 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = exports.MinHeap = void 0;
|
|
7
|
-
var
|
|
7
|
+
var _basics = _interopRequireDefault(require("./basics.js"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
// the following functions are inlined:
|
|
9
10
|
|
|
10
11
|
// const left = i => (i << 1) + 1;
|
|
11
12
|
// const right = i => (i + 1) << 1;
|
|
12
13
|
// const parent = i => (i - 1) >> 1;
|
|
13
14
|
|
|
14
|
-
const defaultLess = (a, b) => a < b;
|
|
15
|
-
const defaultEqual = (a, b) => a === b;
|
|
16
15
|
const up = (array, i, less = defaultLess) => {
|
|
17
16
|
for (let p = i - 1 >> 1; i > 0; i = p, p = i - 1 >> 1) {
|
|
18
17
|
const iValue = array[i],
|
|
@@ -38,15 +37,15 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
38
37
|
}
|
|
39
38
|
return array;
|
|
40
39
|
};
|
|
41
|
-
class MinHeap {
|
|
40
|
+
class MinHeap extends _basics.default {
|
|
42
41
|
constructor(options, ...args) {
|
|
43
|
-
(
|
|
42
|
+
super(options);
|
|
44
43
|
if (typeof this.compare == 'function') {
|
|
45
44
|
this.less = (a, b) => this.compare(a, b) < 0;
|
|
46
45
|
this.equal = (a, b) => !this.compare(a, b);
|
|
47
46
|
}
|
|
48
47
|
this.array = [];
|
|
49
|
-
this.merge(...args);
|
|
48
|
+
if (args.length) this.merge(...args);
|
|
50
49
|
}
|
|
51
50
|
get length() {
|
|
52
51
|
return this.array.length;
|
|
@@ -191,9 +190,6 @@ class MinHeap {
|
|
|
191
190
|
})), this.less);
|
|
192
191
|
return this;
|
|
193
192
|
}
|
|
194
|
-
make(...args) {
|
|
195
|
-
return new MinHeap(this, ...args);
|
|
196
|
-
}
|
|
197
193
|
clone() {
|
|
198
194
|
const heap = new MinHeap(this);
|
|
199
195
|
heap.array = this.array.slice(0);
|
|
@@ -288,11 +284,11 @@ class MinHeap {
|
|
|
288
284
|
}
|
|
289
285
|
return heapArray;
|
|
290
286
|
}
|
|
287
|
+
static from(array, options = MinHeap.defaults) {
|
|
288
|
+
const heap = new MinHeap(options);
|
|
289
|
+
heap.array = MinHeap.build(array, heap.less);
|
|
290
|
+
return heap;
|
|
291
|
+
}
|
|
291
292
|
}
|
|
292
293
|
exports.MinHeap = MinHeap;
|
|
293
|
-
MinHeap.defaults = {
|
|
294
|
-
less: defaultLess,
|
|
295
|
-
equal: defaultEqual,
|
|
296
|
-
compare: null
|
|
297
|
-
};
|
|
298
294
|
var _default = exports.default = MinHeap;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = exports.SkewHeapNode = exports.SkewHeap = void 0;
|
|
7
|
+
var _basics = _interopRequireDefault(require("./basics.js"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
const merge = (a, b, less) => {
|
|
10
|
+
if (!a) return b;
|
|
11
|
+
if (!b) return a;
|
|
12
|
+
if (less(b.value, a.value)) [a, b] = [b, a]; // swap
|
|
13
|
+
|
|
14
|
+
const temp = a.right;
|
|
15
|
+
a.right = a.left;
|
|
16
|
+
a.left = merge(b, temp, less);
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
class SkewHeapNode {
|
|
20
|
+
constructor(value) {
|
|
21
|
+
this.value = value;
|
|
22
|
+
this.right = this.left = null;
|
|
23
|
+
}
|
|
24
|
+
clear() {
|
|
25
|
+
this.left = this.right = null;
|
|
26
|
+
}
|
|
27
|
+
clone() {
|
|
28
|
+
const node = new SkewHeapNode(this.value);
|
|
29
|
+
node.left = this.left && this.left.clone();
|
|
30
|
+
node.right = this.right && this.right.clone();
|
|
31
|
+
return node;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.SkewHeapNode = SkewHeapNode;
|
|
35
|
+
class SkewHeap extends _basics.default {
|
|
36
|
+
constructor(options, ...args) {
|
|
37
|
+
super(options);
|
|
38
|
+
if (typeof this.compare == 'function') {
|
|
39
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
40
|
+
}
|
|
41
|
+
this.root = null;
|
|
42
|
+
this.size = 0;
|
|
43
|
+
if (args.length) this.merge(...args);
|
|
44
|
+
}
|
|
45
|
+
get isEmpty() {
|
|
46
|
+
return !this.root;
|
|
47
|
+
}
|
|
48
|
+
get length() {
|
|
49
|
+
return this.size;
|
|
50
|
+
}
|
|
51
|
+
get top() {
|
|
52
|
+
return this.root ? this.root.value : undefined;
|
|
53
|
+
}
|
|
54
|
+
peek() {
|
|
55
|
+
return this.root ? this.root.value : undefined;
|
|
56
|
+
}
|
|
57
|
+
push(value) {
|
|
58
|
+
this.root = merge(this.root, new SkewHeapNode(value), this.less);
|
|
59
|
+
++this.size;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
pop() {
|
|
63
|
+
if (!this.root) return;
|
|
64
|
+
const z = this.root;
|
|
65
|
+
this.root = merge(this.root.left, this.root.right, this.less);
|
|
66
|
+
--this.size;
|
|
67
|
+
return z.value;
|
|
68
|
+
}
|
|
69
|
+
pushPop(value) {
|
|
70
|
+
if (!this.root || this.less(value, this.root.value)) return value;
|
|
71
|
+
const z = this.root;
|
|
72
|
+
this.root = merge(z.left, new SkewHeapNode(value), this.less);
|
|
73
|
+
this.root = merge(this.root, z.right, this.less);
|
|
74
|
+
return z.value;
|
|
75
|
+
}
|
|
76
|
+
replaceTop(value) {
|
|
77
|
+
if (!this.root) {
|
|
78
|
+
this.root = new SkewHeapNode(value);
|
|
79
|
+
this.size = 1;
|
|
80
|
+
return; // undefined
|
|
81
|
+
}
|
|
82
|
+
const z = this.root;
|
|
83
|
+
this.root = merge(z.left, new SkewHeapNode(value), this.less);
|
|
84
|
+
this.root = merge(this.root, z.right, this.less);
|
|
85
|
+
return z.value;
|
|
86
|
+
}
|
|
87
|
+
clear() {
|
|
88
|
+
this.root = null;
|
|
89
|
+
this.size = 0;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
merge(...args) {
|
|
93
|
+
for (const other of args) {
|
|
94
|
+
this.root = merge(this.root, other.root, this.less);
|
|
95
|
+
this.size += other.size;
|
|
96
|
+
other.root = null;
|
|
97
|
+
other.size = 0;
|
|
98
|
+
}
|
|
99
|
+
return this;
|
|
100
|
+
}
|
|
101
|
+
clone() {
|
|
102
|
+
const heap = new SkewHeap(this);
|
|
103
|
+
heap.root = this.root && this.root.clone();
|
|
104
|
+
heap.size = this.size;
|
|
105
|
+
return heap;
|
|
106
|
+
}
|
|
107
|
+
static from(array, options = _basics.default.defaults) {
|
|
108
|
+
const heap = new SkewHeap(options);
|
|
109
|
+
for (const value of array) heap.push(value);
|
|
110
|
+
return heap;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
exports.SkewHeap = SkewHeap;
|
|
114
|
+
var _default = exports.default = SkewHeap;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "list-toolkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "List-based data structures to organize your objects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"data structures"
|
|
32
32
|
],
|
|
33
33
|
"author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (http://www.lazutkin.com/)",
|
|
34
|
+
"funding": "https://github.com/sponsors/uhop",
|
|
34
35
|
"license": "BSD-3-Clause",
|
|
35
36
|
"bugs": {
|
|
36
37
|
"url": "https://github.com/uhop/list-toolkit/issues"
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"@babel/cli": "^7.25.6",
|
|
41
42
|
"@babel/core": "^7.25.2",
|
|
42
43
|
"@babel/preset-env": "^7.25.4",
|
|
44
|
+
"nano-benchmark": "^1.0.3",
|
|
43
45
|
"tape-six": "^0.12.2"
|
|
44
46
|
},
|
|
45
47
|
"files": [
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import {copyOptions} from '../meta-utils.js';
|
|
4
|
+
|
|
5
|
+
const defaultLess = (a, b) => a < b;
|
|
6
|
+
const defaultEqual = (a, b) => a === b;
|
|
7
|
+
|
|
8
|
+
export class HeapBase {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
copyOptions(this, HeapBase.defaults, options);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// main methods
|
|
14
|
+
get isEmpty() {
|
|
15
|
+
throw new Error('Not implemented');
|
|
16
|
+
}
|
|
17
|
+
get top() {
|
|
18
|
+
throw new Error('Not implemented');
|
|
19
|
+
}
|
|
20
|
+
peek() {
|
|
21
|
+
return this.top;
|
|
22
|
+
}
|
|
23
|
+
pop() {
|
|
24
|
+
throw new Error('Not implemented');
|
|
25
|
+
}
|
|
26
|
+
push() {
|
|
27
|
+
throw new Error('Not implemented');
|
|
28
|
+
}
|
|
29
|
+
clear() {
|
|
30
|
+
throw new Error('Not implemented');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// performance methods
|
|
34
|
+
pushPop(value) {
|
|
35
|
+
this.push(value);
|
|
36
|
+
return this.pop();
|
|
37
|
+
}
|
|
38
|
+
replaceTop(value) {
|
|
39
|
+
const z = this.pop();
|
|
40
|
+
this.push(value);
|
|
41
|
+
return z;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// helper methods
|
|
45
|
+
merge(...args) {
|
|
46
|
+
throw new Error('Not implemented');
|
|
47
|
+
}
|
|
48
|
+
clone() {
|
|
49
|
+
throw new Error('Not implemented');
|
|
50
|
+
}
|
|
51
|
+
make(...args) {
|
|
52
|
+
return new this.constructor(this, ...args);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
HeapBase.defaults = {less: defaultLess, equal: defaultEqual, compare: null};
|
|
57
|
+
|
|
58
|
+
export default HeapBase;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import HeapBase from './basics.js';
|
|
4
|
+
|
|
5
|
+
const defaultLess = (a, b) => a < b;
|
|
6
|
+
|
|
7
|
+
const merge = (a, b, less) => {
|
|
8
|
+
if (!a) return b;
|
|
9
|
+
if (!b) return a;
|
|
10
|
+
if (less(b.value, a.value)) [a, b] = [b, a]; // swap
|
|
11
|
+
|
|
12
|
+
a.right = merge(a.right, b, less);
|
|
13
|
+
|
|
14
|
+
if (!a.left) {
|
|
15
|
+
[a.left, a.right] = [a.right, a.left]; // swap
|
|
16
|
+
a.s = 1;
|
|
17
|
+
return a;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (a.left.s < a.right.s) {
|
|
21
|
+
[a.left, a.right] = [a.right, a.left]; // swap
|
|
22
|
+
}
|
|
23
|
+
a.s = a.right.s + 1;
|
|
24
|
+
return a;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class LeftistHeapNode {
|
|
28
|
+
constructor(value) {
|
|
29
|
+
this.value = value;
|
|
30
|
+
this.right = this.left = null;
|
|
31
|
+
this.s = 1;
|
|
32
|
+
}
|
|
33
|
+
clear() {
|
|
34
|
+
this.left = this.right = null;
|
|
35
|
+
this.s = 1;
|
|
36
|
+
}
|
|
37
|
+
clone() {
|
|
38
|
+
const node = new LeftistHeapNode(this.value);
|
|
39
|
+
node.left = this.left && this.left.clone();
|
|
40
|
+
node.right = this.right && this.right.clone();
|
|
41
|
+
return node;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class LeftistHeap extends HeapBase {
|
|
46
|
+
constructor(options, ...args) {
|
|
47
|
+
super(options);
|
|
48
|
+
if (typeof this.compare == 'function') {
|
|
49
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
50
|
+
}
|
|
51
|
+
this.root = null;
|
|
52
|
+
this.size = 0;
|
|
53
|
+
if (args.length) this.merge(...args);
|
|
54
|
+
}
|
|
55
|
+
get isEmpty() {
|
|
56
|
+
return !this.root;
|
|
57
|
+
}
|
|
58
|
+
get length() {
|
|
59
|
+
return this.size;
|
|
60
|
+
}
|
|
61
|
+
get top() {
|
|
62
|
+
return this.root ? this.root.value : undefined;
|
|
63
|
+
}
|
|
64
|
+
peek() {
|
|
65
|
+
return this.root ? this.root.value : undefined;
|
|
66
|
+
}
|
|
67
|
+
push(value) {
|
|
68
|
+
this.root = merge(this.root, new LeftistHeapNode(value), this.less);
|
|
69
|
+
++this.size;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
pop() {
|
|
73
|
+
if (!this.root) return;
|
|
74
|
+
const z = this.root;
|
|
75
|
+
this.root = merge(this.root.left, this.root.right, this.less);
|
|
76
|
+
--this.size;
|
|
77
|
+
return z.value;
|
|
78
|
+
}
|
|
79
|
+
pushPop(value) {
|
|
80
|
+
if (!this.root || this.less(value, this.root.value)) return value;
|
|
81
|
+
const z = this.root;
|
|
82
|
+
this.root = merge(z.left, new LeftistHeapNode(value), this.less);
|
|
83
|
+
this.root = merge(this.root, z.right, this.less);
|
|
84
|
+
return z.value;
|
|
85
|
+
}
|
|
86
|
+
replaceTop(value) {
|
|
87
|
+
if (!this.root) {
|
|
88
|
+
this.root = new LeftistHeapNode(value);
|
|
89
|
+
this.size = 1;
|
|
90
|
+
return; // undefined
|
|
91
|
+
}
|
|
92
|
+
const z = this.root;
|
|
93
|
+
this.root = merge(z.left, new LeftistHeapNode(value), this.less);
|
|
94
|
+
this.root = merge(this.root, z.right, this.less);
|
|
95
|
+
return z.value;
|
|
96
|
+
}
|
|
97
|
+
clear() {
|
|
98
|
+
this.root = null;
|
|
99
|
+
this.size = 0;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
merge(...args) {
|
|
103
|
+
for (const other of args) {
|
|
104
|
+
this.root = merge(this.root, other.root, this.less);
|
|
105
|
+
this.size += other.size;
|
|
106
|
+
other.root = null;
|
|
107
|
+
other.size = 0;
|
|
108
|
+
}
|
|
109
|
+
return this;
|
|
110
|
+
}
|
|
111
|
+
clone() {
|
|
112
|
+
const heap = new LeftistHeap(this);
|
|
113
|
+
heap.root = this.root && this.root.clone();
|
|
114
|
+
heap.size = this.size;
|
|
115
|
+
return heap;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
static from(array, options = HeapBase.defaults) {
|
|
119
|
+
const heap = new LeftistHeap(options);
|
|
120
|
+
for (const value of array) heap.push(value);
|
|
121
|
+
return heap;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export default LeftistHeap;
|
package/src/heap/min-heap.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import HeapBase from './basics.js';
|
|
4
4
|
|
|
5
5
|
// the following functions are inlined:
|
|
6
6
|
|
|
@@ -8,9 +8,6 @@ import {copyOptions} from '../meta-utils.js';
|
|
|
8
8
|
// const right = i => (i + 1) << 1;
|
|
9
9
|
// const parent = i => (i - 1) >> 1;
|
|
10
10
|
|
|
11
|
-
const defaultLess = (a, b) => a < b;
|
|
12
|
-
const defaultEqual = (a, b) => a === b;
|
|
13
|
-
|
|
14
11
|
const up = (array, i, less = defaultLess) => {
|
|
15
12
|
for (let p = (i - 1) >> 1; i > 0; i = p, p = (i - 1) >> 1) {
|
|
16
13
|
const iValue = array[i],
|
|
@@ -38,15 +35,15 @@ const down = (array, i, less = defaultLess, n = array.length) => {
|
|
|
38
35
|
return array;
|
|
39
36
|
};
|
|
40
37
|
|
|
41
|
-
export class MinHeap {
|
|
38
|
+
export class MinHeap extends HeapBase {
|
|
42
39
|
constructor(options, ...args) {
|
|
43
|
-
|
|
40
|
+
super(options);
|
|
44
41
|
if (typeof this.compare == 'function') {
|
|
45
42
|
this.less = (a, b) => this.compare(a, b) < 0;
|
|
46
43
|
this.equal = (a, b) => !this.compare(a, b);
|
|
47
44
|
}
|
|
48
45
|
this.array = [];
|
|
49
|
-
this.merge(...args);
|
|
46
|
+
if (args.length) this.merge(...args);
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
get length() {
|
|
@@ -216,10 +213,6 @@ export class MinHeap {
|
|
|
216
213
|
return this;
|
|
217
214
|
}
|
|
218
215
|
|
|
219
|
-
make(...args) {
|
|
220
|
-
return new MinHeap(this, ...args);
|
|
221
|
-
}
|
|
222
|
-
|
|
223
216
|
clone() {
|
|
224
217
|
const heap = new MinHeap(this);
|
|
225
218
|
heap.array = this.array.slice(0);
|
|
@@ -327,8 +320,12 @@ export class MinHeap {
|
|
|
327
320
|
}
|
|
328
321
|
return heapArray;
|
|
329
322
|
}
|
|
330
|
-
}
|
|
331
323
|
|
|
332
|
-
|
|
324
|
+
static from(array, options = MinHeap.defaults) {
|
|
325
|
+
const heap = new MinHeap(options);
|
|
326
|
+
heap.array = MinHeap.build(array, heap.less);
|
|
327
|
+
return heap;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
333
330
|
|
|
334
331
|
export default MinHeap;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import HeapBase from './basics.js';
|
|
4
|
+
|
|
5
|
+
const merge = (a, b, less) => {
|
|
6
|
+
if (!a) return b;
|
|
7
|
+
if (!b) return a;
|
|
8
|
+
if (less(b.value, a.value)) [a, b] = [b, a]; // swap
|
|
9
|
+
|
|
10
|
+
const temp = a.right;
|
|
11
|
+
a.right = a.left;
|
|
12
|
+
a.left = merge(b, temp, less);
|
|
13
|
+
|
|
14
|
+
return a;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class SkewHeapNode {
|
|
18
|
+
constructor(value) {
|
|
19
|
+
this.value = value;
|
|
20
|
+
this.right = this.left = null;
|
|
21
|
+
}
|
|
22
|
+
clear() {
|
|
23
|
+
this.left = this.right = null;
|
|
24
|
+
}
|
|
25
|
+
clone() {
|
|
26
|
+
const node = new SkewHeapNode(this.value);
|
|
27
|
+
node.left = this.left && this.left.clone();
|
|
28
|
+
node.right = this.right && this.right.clone();
|
|
29
|
+
return node;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class SkewHeap extends HeapBase {
|
|
34
|
+
constructor(options, ...args) {
|
|
35
|
+
super(options);
|
|
36
|
+
if (typeof this.compare == 'function') {
|
|
37
|
+
this.less = (a, b) => this.compare(a, b) < 0;
|
|
38
|
+
}
|
|
39
|
+
this.root = null;
|
|
40
|
+
this.size = 0;
|
|
41
|
+
if (args.length) this.merge(...args);
|
|
42
|
+
}
|
|
43
|
+
get isEmpty() {
|
|
44
|
+
return !this.root;
|
|
45
|
+
}
|
|
46
|
+
get length() {
|
|
47
|
+
return this.size;
|
|
48
|
+
}
|
|
49
|
+
get top() {
|
|
50
|
+
return this.root ? this.root.value : undefined;
|
|
51
|
+
}
|
|
52
|
+
peek() {
|
|
53
|
+
return this.root ? this.root.value : undefined;
|
|
54
|
+
}
|
|
55
|
+
push(value) {
|
|
56
|
+
this.root = merge(this.root, new SkewHeapNode(value), this.less);
|
|
57
|
+
++this.size;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
pop() {
|
|
61
|
+
if (!this.root) return;
|
|
62
|
+
const z = this.root;
|
|
63
|
+
this.root = merge(this.root.left, this.root.right, this.less);
|
|
64
|
+
--this.size;
|
|
65
|
+
return z.value;
|
|
66
|
+
}
|
|
67
|
+
pushPop(value) {
|
|
68
|
+
if (!this.root || this.less(value, this.root.value)) return value;
|
|
69
|
+
const z = this.root;
|
|
70
|
+
this.root = merge(z.left, new SkewHeapNode(value), this.less);
|
|
71
|
+
this.root = merge(this.root, z.right, this.less);
|
|
72
|
+
return z.value;
|
|
73
|
+
}
|
|
74
|
+
replaceTop(value) {
|
|
75
|
+
if (!this.root) {
|
|
76
|
+
this.root = new SkewHeapNode(value);
|
|
77
|
+
this.size = 1;
|
|
78
|
+
return; // undefined
|
|
79
|
+
}
|
|
80
|
+
const z = this.root;
|
|
81
|
+
this.root = merge(z.left, new SkewHeapNode(value), this.less);
|
|
82
|
+
this.root = merge(this.root, z.right, this.less);
|
|
83
|
+
return z.value;
|
|
84
|
+
}
|
|
85
|
+
clear() {
|
|
86
|
+
this.root = null;
|
|
87
|
+
this.size = 0;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
merge(...args) {
|
|
91
|
+
for (const other of args) {
|
|
92
|
+
this.root = merge(this.root, other.root, this.less);
|
|
93
|
+
this.size += other.size;
|
|
94
|
+
other.root = null;
|
|
95
|
+
other.size = 0;
|
|
96
|
+
}
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
clone() {
|
|
100
|
+
const heap = new SkewHeap(this);
|
|
101
|
+
heap.root = this.root && this.root.clone();
|
|
102
|
+
heap.size = this.size;
|
|
103
|
+
return heap;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static from(array, options = HeapBase.defaults) {
|
|
107
|
+
const heap = new SkewHeap(options);
|
|
108
|
+
for (const value of array) heap.push(value);
|
|
109
|
+
return heap;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export default SkewHeap;
|