UNPKG

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