UNPKG

9.9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.createFibonacciHeapClass = void 0;
7
8var _factory = require("../../utils/factory.js");
9
10var name = 'FibonacciHeap';
11var dependencies = ['smaller', 'larger'];
12var createFibonacciHeapClass = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) {
13 var smaller = _ref.smaller,
14 larger = _ref.larger;
15 var oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0);
16 /**
17 * Fibonacci Heap implementation, used interally for Matrix math.
18 * @class FibonacciHeap
19 * @constructor FibonacciHeap
20 */
21
22 function FibonacciHeap() {
23 if (!(this instanceof FibonacciHeap)) {
24 throw new SyntaxError('Constructor must be called with the new operator');
25 } // initialize fields
26
27
28 this._minimum = null;
29 this._size = 0;
30 }
31 /**
32 * Attach type information
33 */
34
35
36 FibonacciHeap.prototype.type = 'FibonacciHeap';
37 FibonacciHeap.prototype.isFibonacciHeap = true;
38 /**
39 * Inserts a new data element into the heap. No heap consolidation is
40 * performed at this time, the new node is simply inserted into the root
41 * list of this heap. Running time: O(1) actual.
42 * @memberof FibonacciHeap
43 */
44
45 FibonacciHeap.prototype.insert = function (key, value) {
46 // create node
47 var node = {
48 key: key,
49 value: value,
50 degree: 0
51 }; // check we have a node in the minimum
52
53 if (this._minimum) {
54 // minimum node
55 var minimum = this._minimum; // update left & right of node
56
57 node.left = minimum;
58 node.right = minimum.right;
59 minimum.right = node;
60 node.right.left = node; // update minimum node in heap if needed
61
62 if (smaller(key, minimum.key)) {
63 // node has a smaller key, use it as minimum
64 this._minimum = node;
65 }
66 } else {
67 // set left & right
68 node.left = node;
69 node.right = node; // this is the first node
70
71 this._minimum = node;
72 } // increment number of nodes in heap
73
74
75 this._size++; // return node
76
77 return node;
78 };
79 /**
80 * Returns the number of nodes in heap. Running time: O(1) actual.
81 * @memberof FibonacciHeap
82 */
83
84
85 FibonacciHeap.prototype.size = function () {
86 return this._size;
87 };
88 /**
89 * Removes all elements from this heap.
90 * @memberof FibonacciHeap
91 */
92
93
94 FibonacciHeap.prototype.clear = function () {
95 this._minimum = null;
96 this._size = 0;
97 };
98 /**
99 * Returns true if the heap is empty, otherwise false.
100 * @memberof FibonacciHeap
101 */
102
103
104 FibonacciHeap.prototype.isEmpty = function () {
105 return this._size === 0;
106 };
107 /**
108 * Extracts the node with minimum key from heap. Amortized running
109 * time: O(log n).
110 * @memberof FibonacciHeap
111 */
112
113
114 FibonacciHeap.prototype.extractMinimum = function () {
115 // node to remove
116 var node = this._minimum; // check we have a minimum
117
118 if (node === null) {
119 return node;
120 } // current minimum
121
122
123 var minimum = this._minimum; // get number of children
124
125 var numberOfChildren = node.degree; // pointer to the first child
126
127 var x = node.child; // for each child of node do...
128
129 while (numberOfChildren > 0) {
130 // store node in right side
131 var tempRight = x.right; // remove x from child list
132
133 x.left.right = x.right;
134 x.right.left = x.left; // add x to root list of heap
135
136 x.left = minimum;
137 x.right = minimum.right;
138 minimum.right = x;
139 x.right.left = x; // set Parent[x] to null
140
141 x.parent = null;
142 x = tempRight;
143 numberOfChildren--;
144 } // remove node from root list of heap
145
146
147 node.left.right = node.right;
148 node.right.left = node.left; // update minimum
149
150 if (node === node.right) {
151 // empty
152 minimum = null;
153 } else {
154 // update minimum
155 minimum = node.right; // we need to update the pointer to the root with minimum key
156
157 minimum = _findMinimumNode(minimum, this._size);
158 } // decrement size of heap
159
160
161 this._size--; // update minimum
162
163 this._minimum = minimum; // return node
164
165 return node;
166 };
167 /**
168 * Removes a node from the heap given the reference to the node. The trees
169 * in the heap will be consolidated, if necessary. This operation may fail
170 * to remove the correct element if there are nodes with key value -Infinity.
171 * Running time: O(log n) amortized.
172 * @memberof FibonacciHeap
173 */
174
175
176 FibonacciHeap.prototype.remove = function (node) {
177 // decrease key value
178 this._minimum = _decreaseKey(this._minimum, node, -1); // remove the smallest
179
180 this.extractMinimum();
181 };
182 /**
183 * Decreases the key value for a heap node, given the new value to take on.
184 * The structure of the heap may be changed and will not be consolidated.
185 * Running time: O(1) amortized.
186 * @memberof FibonacciHeap
187 */
188
189
190 function _decreaseKey(minimum, node, key) {
191 // set node key
192 node.key = key; // get parent node
193
194 var parent = node.parent;
195
196 if (parent && smaller(node.key, parent.key)) {
197 // remove node from parent
198 _cut(minimum, node, parent); // remove all nodes from parent to the root parent
199
200
201 _cascadingCut(minimum, parent);
202 } // update minimum node if needed
203
204
205 if (smaller(node.key, minimum.key)) {
206 minimum = node;
207 } // return minimum
208
209
210 return minimum;
211 }
212 /**
213 * The reverse of the link operation: removes node from the child list of parent.
214 * This method assumes that min is non-null. Running time: O(1).
215 * @memberof FibonacciHeap
216 */
217
218
219 function _cut(minimum, node, parent) {
220 // remove node from parent children and decrement Degree[parent]
221 node.left.right = node.right;
222 node.right.left = node.left;
223 parent.degree--; // reset y.child if necessary
224
225 if (parent.child === node) {
226 parent.child = node.right;
227 } // remove child if degree is 0
228
229
230 if (parent.degree === 0) {
231 parent.child = null;
232 } // add node to root list of heap
233
234
235 node.left = minimum;
236 node.right = minimum.right;
237 minimum.right = node;
238 node.right.left = node; // set parent[node] to null
239
240 node.parent = null; // set mark[node] to false
241
242 node.mark = false;
243 }
244 /**
245 * Performs a cascading cut operation. This cuts node from its parent and then
246 * does the same for its parent, and so on up the tree.
247 * Running time: O(log n); O(1) excluding the recursion.
248 * @memberof FibonacciHeap
249 */
250
251
252 function _cascadingCut(minimum, node) {
253 // store parent node
254 var parent = node.parent; // if there's a parent...
255
256 if (!parent) {
257 return;
258 } // if node is unmarked, set it marked
259
260
261 if (!node.mark) {
262 node.mark = true;
263 } else {
264 // it's marked, cut it from parent
265 _cut(minimum, node, parent); // cut its parent as well
266
267
268 _cascadingCut(parent);
269 }
270 }
271 /**
272 * Make the first node a child of the second one. Running time: O(1) actual.
273 * @memberof FibonacciHeap
274 */
275
276
277 var _linkNodes = function _linkNodes(node, parent) {
278 // remove node from root list of heap
279 node.left.right = node.right;
280 node.right.left = node.left; // make node a Child of parent
281
282 node.parent = parent;
283
284 if (!parent.child) {
285 parent.child = node;
286 node.right = node;
287 node.left = node;
288 } else {
289 node.left = parent.child;
290 node.right = parent.child.right;
291 parent.child.right = node;
292 node.right.left = node;
293 } // increase degree[parent]
294
295
296 parent.degree++; // set mark[node] false
297
298 node.mark = false;
299 };
300
301 function _findMinimumNode(minimum, size) {
302 // to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree
303 var arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1; // create list with initial capacity
304
305 var array = new Array(arraySize); // find the number of root nodes.
306
307 var numRoots = 0;
308 var x = minimum;
309
310 if (x) {
311 numRoots++;
312 x = x.right;
313
314 while (x !== minimum) {
315 numRoots++;
316 x = x.right;
317 }
318 } // vars
319
320
321 var y; // For each node in root list do...
322
323 while (numRoots > 0) {
324 // access this node's degree..
325 var d = x.degree; // get next node
326
327 var next = x.right; // check if there is a node already in array with the same degree
328
329 while (true) {
330 // get node with the same degree is any
331 y = array[d];
332
333 if (!y) {
334 break;
335 } // make one node with the same degree a child of the other, do this based on the key value.
336
337
338 if (larger(x.key, y.key)) {
339 var temp = y;
340 y = x;
341 x = temp;
342 } // make y a child of x
343
344
345 _linkNodes(y, x); // we have handled this degree, go to next one.
346
347
348 array[d] = null;
349 d++;
350 } // save this node for later when we might encounter another of the same degree.
351
352
353 array[d] = x; // move forward through list.
354
355 x = next;
356 numRoots--;
357 } // Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[].
358
359
360 minimum = null; // loop nodes in array
361
362 for (var i = 0; i < arraySize; i++) {
363 // get current node
364 y = array[i];
365
366 if (!y) {
367 continue;
368 } // check if we have a linked list
369
370
371 if (minimum) {
372 // First remove node from root list.
373 y.left.right = y.right;
374 y.right.left = y.left; // now add to root list, again.
375
376 y.left = minimum;
377 y.right = minimum.right;
378 minimum.right = y;
379 y.right.left = y; // check if this is a new min.
380
381 if (smaller(y.key, minimum.key)) {
382 minimum = y;
383 }
384 } else {
385 minimum = y;
386 }
387 }
388
389 return minimum;
390 }
391
392 return FibonacciHeap;
393}, {
394 isClass: true
395});
396exports.createFibonacciHeapClass = createFibonacciHeapClass;
\No newline at end of file