|
| 1 | +/* |
| 2 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 3 | +you may not use this file except in compliance with the License. |
| 4 | +You may obtain a copy of the License at |
| 5 | +
|
| 6 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | +
|
| 8 | +Unless required by applicable law or agreed to in writing, software |
| 9 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 10 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 11 | +See the License for the specific language governing permissions and |
| 12 | +limitations under the License. |
| 13 | +
|
| 14 | +Special thanks to Keith Schwarz ([email protected]), |
| 15 | +whose code and documentation have been used as a reference |
| 16 | +for the algorithm implementation. |
| 17 | +http://www.keithschwarz.com/interesting/code/?dir=fibonacci-heap |
| 18 | +*/ |
| 19 | + |
| 20 | +/* |
| 21 | +* An implementation of a priority queue backed by a Fibonacci heap, |
| 22 | +* as described by Fredman and Tarjan. Fibonacci heaps are interesting |
| 23 | +* theoretically because they have asymptotically good runtime guarantees |
| 24 | +* for many operations. In particular, insert, peek, and decrease-key all |
| 25 | +* run in amortized O(1) time. dequeueMin and delete each run in amortized |
| 26 | +* O(lg n) time. This allows algorithms that rely heavily on decrease-key |
| 27 | +* to gain significant performance boosts. For example, Dijkstra's algorithm |
| 28 | +* for single-source shortest paths can be shown to run in O(m + n lg n) using |
| 29 | +* a Fibonacci heap, compared to O(m lg n) using a standard binary or binomial |
| 30 | +* heap. |
| 31 | +* |
| 32 | +* Internally, a Fibonacci heap is represented as a circular, doubly-linked |
| 33 | +* list of trees obeying the min-heap property. Each node stores pointers |
| 34 | +* to its parent (if any) and some arbitrary child. Additionally, every |
| 35 | +* node stores its degree (the number of children it has) and whether it |
| 36 | +* is a "marked" node. Finally, each Fibonacci heap stores a pointer to |
| 37 | +* the tree with the minimum value. |
| 38 | +* |
| 39 | +* To insert a node into a Fibonacci heap, a singleton tree is created and |
| 40 | +* merged into the rest of the trees. The merge operation works by simply |
| 41 | +* splicing together the doubly-linked lists of the two trees, then updating |
| 42 | +* the min pointer to be the smaller of the minima of the two heaps. Peeking |
| 43 | +* at the smallest element can therefore be accomplished by just looking at |
| 44 | +* the min element. All of these operations complete in O(1) time. |
| 45 | +* |
| 46 | +* The tricky operations are dequeueMin and decreaseKey. dequeueMin works |
| 47 | +* by removing the root of the tree containing the smallest element, then |
| 48 | +* merging its children with the topmost roots. Then, the roots are scanned |
| 49 | +* and merged so that there is only one tree of each degree in the root list. |
| 50 | +* This works by maintaining a dynamic array of trees, each initially null, |
| 51 | +* pointing to the roots of trees of each dimension. The list is then scanned |
| 52 | +* and this array is populated. Whenever a conflict is discovered, the |
| 53 | +* appropriate trees are merged together until no more conflicts exist. The |
| 54 | +* resulting trees are then put into the root list. A clever analysis using |
| 55 | +* the potential method can be used to show that the amortized cost of this |
| 56 | +* operation is O(lg n), see "Introduction to Algorithms, Second Edition" by |
| 57 | +* Cormen, Rivest, Leiserson, and Stein for more details. |
| 58 | +* |
| 59 | +* The other hard operation is decreaseKey, which works as follows. First, we |
| 60 | +* update the key of the node to be the new value. If this leaves the node |
| 61 | +* smaller than its parent, we're done. Otherwise, we cut the node from its |
| 62 | +* parent, add it as a root, and then mark its parent. If the parent was |
| 63 | +* already marked, we cut that node as well, recursively mark its parent, |
| 64 | +* and continue this process. This can be shown to run in O(1) amortized time |
| 65 | +* using yet another clever potential function. Finally, given this function, |
| 66 | +* we can implement delete by decreasing a key to -\infty, then calling |
| 67 | +* dequeueMin to extract it. |
| 68 | + */ |
| 69 | + |
| 70 | +package fibheap |
| 71 | + |
| 72 | +import ( |
| 73 | + "fmt" |
| 74 | + "math" |
| 75 | +) |
| 76 | + |
| 77 | +/****************************************** |
| 78 | + ************** INTERFACE ***************** |
| 79 | + ******************************************/ |
| 80 | + |
| 81 | +// The FloatingFibonacciHeap is an implementation of a fibonacci heap |
| 82 | +// with only floating-point priorities and no user data attached. |
| 83 | +type FloatingFibonacciHeap interface { |
| 84 | + // Adds and element to the heap |
| 85 | + Enqueue(priority float64) *Entry |
| 86 | + // Returns the minimum element in the heap |
| 87 | + Min() (*Entry, error) |
| 88 | + // Is the heap empty? |
| 89 | + IsEmpty() bool |
| 90 | + // The number of elements in the heap |
| 91 | + Size() uint |
| 92 | + // Removes and returns the minimal element |
| 93 | + // in the heap |
| 94 | + DequeueMin() (*Entry, error) |
| 95 | + // Decreases the key of the given element |
| 96 | + // and sets it to the new given priority |
| 97 | + // returns the node if succesfully set |
| 98 | + DecreaseKey(node *Entry, newPriority float64) (*Entry, error) |
| 99 | + // Deletes the given element in the heap |
| 100 | + Delete(node *Entry) error |
| 101 | + // Will merge two heaps |
| 102 | + Merge(otherHeap FloatingFibonacciHeap) (FloatingFibonacciHeap, error) |
| 103 | +} |
| 104 | + |
| 105 | +// Entry is the entry type that will be used |
| 106 | +// for each node of the Fibonacci heap |
| 107 | +type Entry struct { |
| 108 | + degree int |
| 109 | + marked bool |
| 110 | + next, prev, child, parent *Entry |
| 111 | + priority float64 |
| 112 | +} |
| 113 | + |
| 114 | +/****************************************** |
| 115 | + ************** END INTERFACE ************* |
| 116 | + ******************************************/ |
| 117 | + |
| 118 | +type fibHeap struct { |
| 119 | + min *Entry // The minimal element |
| 120 | + size uint // Size of the heap |
| 121 | +} |
| 122 | + |
| 123 | +// **************** |
| 124 | +// HELPER FUNCTIONS |
| 125 | +// **************** |
| 126 | + |
| 127 | +func newEntry(priority float64) *Entry { |
| 128 | + result := new(Entry) |
| 129 | + result.degree = 0 |
| 130 | + result.marked = false |
| 131 | + result.child = nil |
| 132 | + result.parent = nil |
| 133 | + result.next = result |
| 134 | + result.prev = result |
| 135 | + result.priority = priority |
| 136 | + return result |
| 137 | +} |
| 138 | + |
| 139 | +// *********** |
| 140 | +// ACTUAL CODE |
| 141 | +// *********** |
| 142 | + |
| 143 | +/* |
| 144 | +NewFloatFibHeap creates a new, empty, Fibonacci heap object. |
| 145 | +
|
| 146 | +Remember that it's actually *fibHeap and not fibHeap |
| 147 | +that fulfills the contract of the interface. |
| 148 | +*/ |
| 149 | +func NewFloatFibHeap() FloatingFibonacciHeap { return &fibHeap{nil, 0} } |
| 150 | + |
| 151 | +func (heap *fibHeap) Enqueue(priority float64) *Entry { |
| 152 | + singleton := newEntry(priority) |
| 153 | + |
| 154 | + // Merge singleton list with heap |
| 155 | + heap.min = mergeLists(heap.min, singleton) |
| 156 | + heap.size++ |
| 157 | + return singleton |
| 158 | +} |
| 159 | + |
| 160 | +func (heap *fibHeap) Min() (*Entry, error) { |
| 161 | + if heap.IsEmpty() { |
| 162 | + return nil, fmt.Errorf("Trying to get minimum element of empty heap") |
| 163 | + } |
| 164 | + return heap.min, nil |
| 165 | +} |
| 166 | + |
| 167 | +func (heap *fibHeap) IsEmpty() bool { |
| 168 | + return heap.size == 0 |
| 169 | +} |
| 170 | + |
| 171 | +func (heap *fibHeap) Size() uint { |
| 172 | + return heap.size |
| 173 | +} |
| 174 | + |
| 175 | +func (heap *fibHeap) DequeueMin() (*Entry, error) { |
| 176 | + if heap.IsEmpty() { |
| 177 | + return nil, fmt.Errorf("Heap is empty") |
| 178 | + } |
| 179 | + |
| 180 | + heap.size-- |
| 181 | + |
| 182 | + // Copy pointer. Will need it later. |
| 183 | + min := heap.min |
| 184 | + |
| 185 | + if min.next == min { // This is the only root node |
| 186 | + heap.min = nil |
| 187 | + } else { // There are more root nodes |
| 188 | + heap.min.prev.next = heap.min.next |
| 189 | + heap.min.next.prev = heap.min.prev |
| 190 | + heap.min = heap.min.next // Arbitrary element of the root list |
| 191 | + } |
| 192 | + |
| 193 | + if min.child != nil { |
| 194 | + // Keep track of the first visited node |
| 195 | + curr := min.child |
| 196 | + for ok := true; ok; ok = (curr != min.child) { |
| 197 | + curr.parent = nil |
| 198 | + curr = curr.next |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + heap.min = mergeLists(heap.min, min.child) |
| 203 | + |
| 204 | + if heap.min == nil { |
| 205 | + // If there are no entries left, we're done. |
| 206 | + return min, nil |
| 207 | + } |
| 208 | + |
| 209 | + treeSlice := make([]*Entry, 0, heap.size) |
| 210 | + toVisit := make([]*Entry, 0, heap.size) |
| 211 | + |
| 212 | + for curr := heap.min; len(toVisit) == 0 || toVisit[0] != curr; curr = curr.next { |
| 213 | + toVisit = append(toVisit, curr) |
| 214 | + } |
| 215 | + |
| 216 | + for _, curr := range toVisit { |
| 217 | + for { |
| 218 | + for curr.degree >= len(treeSlice) { |
| 219 | + treeSlice = append(treeSlice, nil) |
| 220 | + } |
| 221 | + |
| 222 | + if treeSlice[curr.degree] == nil { |
| 223 | + treeSlice[curr.degree] = curr |
| 224 | + break |
| 225 | + } |
| 226 | + |
| 227 | + other := treeSlice[curr.degree] |
| 228 | + treeSlice[curr.degree] = nil |
| 229 | + |
| 230 | + // Determine which of two trees has the smaller root |
| 231 | + var minT, maxT *Entry |
| 232 | + if other.priority < curr.priority { |
| 233 | + minT = other |
| 234 | + maxT = curr |
| 235 | + } else { |
| 236 | + minT = curr |
| 237 | + maxT = other |
| 238 | + } |
| 239 | + |
| 240 | + // Break max out of the root list, |
| 241 | + // then merge it into min's child list |
| 242 | + maxT.next.prev = maxT.prev |
| 243 | + maxT.prev.next = maxT.next |
| 244 | + |
| 245 | + // Make it a singleton so that we can merge it |
| 246 | + maxT.prev = maxT |
| 247 | + maxT.next = maxT |
| 248 | + minT.child = mergeLists(minT.child, maxT) |
| 249 | + |
| 250 | + // Reparent max appropriately |
| 251 | + maxT.parent = minT |
| 252 | + |
| 253 | + // Clear max's mark, since it can now lose another child |
| 254 | + maxT.marked = false |
| 255 | + |
| 256 | + // Increase min's degree. It has another child. |
| 257 | + minT.degree++ |
| 258 | + |
| 259 | + // Continue merging this tree |
| 260 | + curr = minT |
| 261 | + } |
| 262 | + |
| 263 | + /* Update the global min based on this node. Note that we compare |
| 264 | + * for <= instead of < here. That's because if we just did a |
| 265 | + * reparent operation that merged two different trees of equal |
| 266 | + * priority, we need to make sure that the min pointer points to |
| 267 | + * the root-level one. |
| 268 | + */ |
| 269 | + if curr.priority <= heap.min.priority { |
| 270 | + heap.min = curr |
| 271 | + } |
| 272 | + } |
| 273 | + |
| 274 | + // All done. Return minimum element and no error |
| 275 | + return min, nil |
| 276 | +} |
| 277 | + |
| 278 | +func (heap *fibHeap) DecreaseKey(node *Entry, newPriority float64) (*Entry, error) { |
| 279 | + |
| 280 | + if newPriority > node.priority { |
| 281 | + return nil, fmt.Errorf("The given new priority is larger than the old") |
| 282 | + } |
| 283 | + |
| 284 | + decreaseKeyUnchecked(heap, node, newPriority) |
| 285 | + return node, nil |
| 286 | +} |
| 287 | + |
| 288 | +func (heap *fibHeap) Delete(node *Entry) error { |
| 289 | + |
| 290 | + decreaseKeyUnchecked(heap, node, -math.MaxFloat64) |
| 291 | + heap.DequeueMin() |
| 292 | + return nil |
| 293 | +} |
| 294 | + |
| 295 | +/* |
| 296 | + * Given two Fibonacci heaps, returns a new Fibonacci heap that contains |
| 297 | + * all of the elements of the two heaps. Each of the input heaps is |
| 298 | + * destructively modified by having all its elements removed. You can |
| 299 | + * continue to use those heaps, but be aware that they will be empty |
| 300 | + * after this call completes. |
| 301 | + */ |
| 302 | +func (heap *fibHeap) Merge(other FloatingFibonacciHeap) (FloatingFibonacciHeap, error) { |
| 303 | + |
| 304 | + otherHeap, ok := other.(*fibHeap) |
| 305 | + if !ok { |
| 306 | + // throw an error |
| 307 | + return nil, fmt.Errorf("The passed object is of type %T, not of internal type *fibHeap. Please provide your own implementation of merge", other) |
| 308 | + } |
| 309 | + |
| 310 | + resultSize := heap.size + otherHeap.size |
| 311 | + |
| 312 | + resultMin := mergeLists(heap.min, otherHeap.min) |
| 313 | + |
| 314 | + heap.min = nil |
| 315 | + otherHeap.min = nil |
| 316 | + heap.size = 0 |
| 317 | + otherHeap.size = 0 |
| 318 | + |
| 319 | + return &fibHeap{resultMin, resultSize}, nil |
| 320 | +} |
| 321 | + |
| 322 | +func mergeLists(one, two *Entry) *Entry { |
| 323 | + if one == nil && two == nil { |
| 324 | + return nil |
| 325 | + } else if one != nil && two == nil { |
| 326 | + return one |
| 327 | + } else if one == nil && two != nil { |
| 328 | + return two |
| 329 | + } |
| 330 | + // Both trees non-null; actually do the merge. |
| 331 | + oneNext := one.next |
| 332 | + one.next = two.next |
| 333 | + one.next.prev = one |
| 334 | + two.next = oneNext |
| 335 | + two.next.prev = two |
| 336 | + |
| 337 | + if one.priority < two.priority { |
| 338 | + return one |
| 339 | + } |
| 340 | + return two |
| 341 | + |
| 342 | +} |
| 343 | + |
| 344 | +func decreaseKeyUnchecked(heap *fibHeap, node *Entry, priority float64) { |
| 345 | + node.priority = priority |
| 346 | + |
| 347 | + if node.parent != nil && node.priority <= node.parent.priority { |
| 348 | + cutNode(heap, node) |
| 349 | + } |
| 350 | + |
| 351 | + if node.priority <= heap.min.priority { |
| 352 | + heap.min = node |
| 353 | + } |
| 354 | +} |
| 355 | + |
| 356 | +func cutNode(heap *fibHeap, node *Entry) { |
| 357 | + node.marked = false |
| 358 | + |
| 359 | + if node.parent == nil { |
| 360 | + return |
| 361 | + } |
| 362 | + |
| 363 | + // Rewire siblings if it has any |
| 364 | + if node.next != node { |
| 365 | + node.next.prev = node.prev |
| 366 | + node.prev.next = node.next |
| 367 | + } |
| 368 | + |
| 369 | + // Rewrite pointer if this is the representative child node |
| 370 | + if node.parent.child == node { |
| 371 | + if node.next != node { |
| 372 | + node.parent.child = node.next |
| 373 | + } else { |
| 374 | + node.parent.child = nil |
| 375 | + } |
| 376 | + } |
| 377 | + |
| 378 | + node.parent.degree-- |
| 379 | + |
| 380 | + node.prev = node |
| 381 | + node.next = node |
| 382 | + heap.min = mergeLists(heap.min, node) |
| 383 | + |
| 384 | + // cut parent recursively if marked |
| 385 | + if node.parent.marked { |
| 386 | + cutNode(heap, node.parent) |
| 387 | + } else { |
| 388 | + node.parent.marked = true |
| 389 | + } |
| 390 | + |
| 391 | + node.parent = nil |
| 392 | +} |
0 commit comments