1 /** 2 * Copyright (c) 2007-2017, Gaudenz Alder 3 * Copyright (c) 2007-2017, JGraph Ltd 4 */ 5 package com.mxgraph.analysis; 6 7 import java.util.Hashtable; 8 import java.util.Map; 9 10 /** 11 * This class implements a priority queue. 12 */ 13 public class mxFibonacciHeap 14 { 15 16 /** 17 * Maps from elements to nodes 18 */ 19 protected Map<Object, Node> nodes = new Hashtable<Object, Node>(); 20 21 /** 22 * 23 */ 24 protected Node min; 25 26 /** 27 * 28 */ 29 protected int size; 30 31 /** 32 * Returns the node that represents element. 33 * @param element the element whose node to find 34 * @param create whether to create 35 * @return the node representing the specified element 36 */ getNode(Object element, boolean create)37 public Node getNode(Object element, boolean create) 38 { 39 Node node = nodes.get(element); 40 41 if (node == null && create) 42 { 43 node = new Node(element, Double.MAX_VALUE); 44 nodes.put(element, node); 45 insert(node, node.getKey()); 46 } 47 return node; 48 } 49 50 /** 51 * Returns true if the queue is empty. 52 * @return whether the queue is empty 53 */ isEmpty()54 public boolean isEmpty() 55 { 56 return min == null; 57 } 58 59 /** 60 * Decreases the key value for a heap node, given the new value to take on. 61 * The structure of the heap may be changed and will not be consolidated. 62 * 63 * <p> 64 * Running time: O(1) amortized 65 * </p> 66 * 67 * @param x Node whose value should be decreased. 68 * @param k New key value for node x. 69 * 70 * @exception IllegalArgumentException 71 * Thrown if k is larger than x.key value. 72 */ decreaseKey(Node x, double k)73 public void decreaseKey(Node x, double k) 74 { 75 if (k > x.key) 76 { 77 throw new IllegalArgumentException( 78 "decreaseKey() got larger key value"); 79 } 80 81 x.key = k; 82 Node y = x.parent; 83 84 if ((y != null) && (x.key < y.key)) 85 { 86 cut(x, y); 87 cascadingCut(y); 88 } 89 90 if (min == null || x.key < min.key) 91 { 92 min = x; 93 } 94 } 95 96 /** 97 * Deletes a node from the heap given the reference to the node. The trees 98 * in the heap will be consolidated, if necessary. This operation may fail 99 * to remove the correct element if there are nodes with key value 100 * -Infinity. 101 * 102 * <p> 103 * Running time: O(log n) amortized 104 * </p> 105 * 106 * @param x The node to remove from the heap. 107 */ delete(Node x)108 public void delete(Node x) 109 { 110 // make x as small as possible 111 decreaseKey(x, Double.NEGATIVE_INFINITY); 112 113 // remove the smallest, which decreases n also 114 removeMin(); 115 } 116 117 /** 118 * Inserts a new data element into the heap. No heap consolidation is 119 * performed at this time, the new node is simply inserted into the root 120 * list of this heap. 121 * 122 * <p> 123 * Running time: O(1) actual 124 * </p> 125 * 126 * @param node 127 * new node to insert into heap 128 * @param key 129 * key value associated with data object 130 */ insert(Node node, double key)131 public void insert(Node node, double key) 132 { 133 node.key = key; 134 135 // concatenate node into min list 136 if (min != null) 137 { 138 node.left = min; 139 node.right = min.right; 140 min.right = node; 141 node.right.left = node; 142 143 if (key < min.key) 144 { 145 min = node; 146 } 147 } 148 else 149 { 150 min = node; 151 } 152 153 size++; 154 } 155 156 /** 157 * Returns the smallest element in the heap. This smallest element is the 158 * one with the minimum key value. 159 * 160 * <p> 161 * Running time: O(1) actual 162 * </p> 163 * 164 * @return Returns the heap node with the smallest key. 165 */ min()166 public Node min() 167 { 168 return min; 169 } 170 171 /** 172 * Removes the smallest element from the heap. This will cause the trees in 173 * the heap to be consolidated, if necessary. 174 * Does not remove the data node so that the current key remains stored. 175 * 176 * <p> 177 * Running time: O(log n) amortized 178 * </p> 179 * 180 * @return Returns the node with the smallest key. 181 */ removeMin()182 public Node removeMin() 183 { 184 Node z = min; 185 186 if (z != null) 187 { 188 int numKids = z.degree; 189 Node x = z.child; 190 Node tempRight; 191 192 // for each child of z do... 193 while (numKids > 0) 194 { 195 tempRight = x.right; 196 197 // remove x from child list 198 x.left.right = x.right; 199 x.right.left = x.left; 200 201 // add x to root list of heap 202 x.left = min; 203 x.right = min.right; 204 min.right = x; 205 x.right.left = x; 206 207 // set parent[x] to null 208 x.parent = null; 209 x = tempRight; 210 numKids--; 211 } 212 213 // remove z from root list of heap 214 z.left.right = z.right; 215 z.right.left = z.left; 216 217 if (z == z.right) 218 { 219 min = null; 220 } 221 else 222 { 223 min = z.right; 224 consolidate(); 225 } 226 227 // decrement size of heap 228 size--; 229 } 230 231 return z; 232 } 233 234 /** 235 * Returns the size of the heap which is measured in the number of elements 236 * contained in the heap. 237 * 238 * <p> 239 * Running time: O(1) actual 240 * </p> 241 * 242 * @return Returns the number of elements in the heap. 243 */ size()244 public int size() 245 { 246 return size; 247 } 248 249 /** 250 * Joins two Fibonacci heaps into a new one. No heap consolidation is 251 * performed at this time. The two root lists are simply joined together. 252 * 253 * <p> 254 * Running time: O(1) actual 255 * </p> 256 * 257 * @param h1 The first heap. 258 * @param h2 The second heap. 259 * @return Returns a new heap containing h1 and h2. 260 */ union(mxFibonacciHeap h1, mxFibonacciHeap h2)261 public static mxFibonacciHeap union(mxFibonacciHeap h1, mxFibonacciHeap h2) 262 { 263 mxFibonacciHeap h = new mxFibonacciHeap(); 264 265 if ((h1 != null) && (h2 != null)) 266 { 267 h.min = h1.min; 268 269 if (h.min != null) 270 { 271 if (h2.min != null) 272 { 273 h.min.right.left = h2.min.left; 274 h2.min.left.right = h.min.right; 275 h.min.right = h2.min; 276 h2.min.left = h.min; 277 278 if (h2.min.key < h1.min.key) 279 { 280 h.min = h2.min; 281 } 282 } 283 } 284 else 285 { 286 h.min = h2.min; 287 } 288 289 h.size = h1.size + h2.size; 290 } 291 292 return h; 293 } 294 295 /** 296 * Performs a cascading cut operation. This cuts y from its parent and then 297 * does the same for its parent, and so on up the tree. 298 * 299 * <p> 300 * Running time: O(log n); O(1) excluding the recursion 301 * </p> 302 * 303 * @param y The node to perform cascading cut on. 304 */ cascadingCut(Node y)305 protected void cascadingCut(Node y) 306 { 307 Node z = y.parent; 308 309 // if there's a parent... 310 if (z != null) 311 { 312 // if y is unmarked, set it marked 313 if (!y.mark) 314 { 315 y.mark = true; 316 } 317 else 318 { 319 // it's marked, cut it from parent 320 cut(y, z); 321 322 // cut its parent as well 323 cascadingCut(z); 324 } 325 } 326 } 327 328 /** 329 * Consolidates the trees in the heap by joining trees of equal degree until 330 * there are no more trees of equal degree in the root list. 331 * 332 * <p> 333 * Running time: O(log n) amortized 334 * </p> 335 */ consolidate()336 protected void consolidate() 337 { 338 int arraySize = size + 1; 339 Node[] array = new Node[arraySize]; 340 341 // Initialize degree array 342 for (int i = 0; i < arraySize; i++) 343 { 344 array[i] = null; 345 } 346 347 // Find the number of root nodes. 348 int numRoots = 0; 349 Node x = min; 350 351 if (x != null) 352 { 353 numRoots++; 354 x = x.right; 355 356 while (x != min) 357 { 358 numRoots++; 359 x = x.right; 360 } 361 } 362 363 // For each node in root list do... 364 while (numRoots > 0) 365 { 366 // Access this node's degree.. 367 int d = x.degree; 368 Node next = x.right; 369 370 // ..and see if there's another of the same degree. 371 while (array[d] != null) 372 { 373 // There is, make one of the nodes a child of the other. 374 Node y = array[d]; 375 376 // Do this based on the key value. 377 if (x.key > y.key) 378 { 379 Node temp = y; 380 y = x; 381 x = temp; 382 } 383 384 // Node y disappears from root list. 385 link(y, x); 386 387 // We've handled this degree, go to next one. 388 array[d] = null; 389 d++; 390 } 391 392 // Save this node for later when we might encounter another 393 // of the same degree. 394 array[d] = x; 395 396 // Move forward through list. 397 x = next; 398 numRoots--; 399 } 400 401 // Set min to null (effectively losing the root list) and 402 // reconstruct the root list from the array entries in array[]. 403 min = null; 404 405 for (int i = 0; i < arraySize; i++) 406 { 407 if (array[i] != null) 408 { 409 // We've got a live one, add it to root list. 410 if (min != null) 411 { 412 // First remove node from root list. 413 array[i].left.right = array[i].right; 414 array[i].right.left = array[i].left; 415 416 // Now add to root list, again. 417 array[i].left = min; 418 array[i].right = min.right; 419 min.right = array[i]; 420 array[i].right.left = array[i]; 421 422 // Check if this is a new min. 423 if (array[i].key < min.key) 424 { 425 min = array[i]; 426 } 427 } 428 else 429 { 430 min = array[i]; 431 } 432 } 433 } 434 } 435 436 /** 437 * The reverse of the link operation: removes x from the child list of y. 438 * This method assumes that min is non-null. 439 * 440 * <p> 441 * Running time: O(1) 442 * </p> 443 * 444 * @param x The child of y to be removed from y's child list. 445 * @param y The parent of x about to lose a child. 446 */ cut(Node x, Node y)447 protected void cut(Node x, Node y) 448 { 449 // remove x from childlist of y and decrement degree[y] 450 x.left.right = x.right; 451 x.right.left = x.left; 452 y.degree--; 453 454 // reset y.child if necessary 455 if (y.child == x) 456 { 457 y.child = x.right; 458 } 459 460 if (y.degree == 0) 461 { 462 y.child = null; 463 } 464 465 // add x to root list of heap 466 x.left = min; 467 x.right = min.right; 468 min.right = x; 469 x.right.left = x; 470 471 // set parent[x] to nil 472 x.parent = null; 473 474 // set mark[x] to false 475 x.mark = false; 476 } 477 478 /** 479 * Make node y a child of node x. 480 * 481 * <p> 482 * Running time: O(1) actual 483 * </p> 484 * 485 * @param y The node to become child. 486 * @param x The node to become parent. 487 */ link(Node y, Node x)488 protected void link(Node y, Node x) 489 { 490 // remove y from root list of heap 491 y.left.right = y.right; 492 y.right.left = y.left; 493 494 // make y a child of x 495 y.parent = x; 496 497 if (x.child == null) 498 { 499 x.child = y; 500 y.right = y; 501 y.left = y; 502 } 503 else 504 { 505 y.left = x.child; 506 y.right = x.child.right; 507 x.child.right = y; 508 y.right.left = y; 509 } 510 511 // increase degree[x] 512 x.degree++; 513 514 // set mark[y] false 515 y.mark = false; 516 } 517 518 /** 519 * Implements a node of the Fibonacci heap. It holds the information 520 * necessary for maintaining the structure of the heap. It also holds the 521 * reference to the key value (which is used to determine the heap 522 * structure). Additional Node data should be stored in a subclass. 523 */ 524 public static class Node 525 { 526 527 Object userObject; 528 529 /** 530 * first child node 531 */ 532 Node child; 533 534 /** 535 * left sibling node 536 */ 537 Node left; 538 539 /** 540 * parent node 541 */ 542 Node parent; 543 544 /** 545 * right sibling node 546 */ 547 Node right; 548 549 /** 550 * true if this node has had a child removed since this node was added 551 * to its parent 552 */ 553 boolean mark; 554 555 /** 556 * key value for this node 557 */ 558 double key; 559 560 /** 561 * number of children of this node (does not count grandchildren) 562 */ 563 int degree; 564 565 /** 566 * Default constructor. Initializes the right and left pointers, making 567 * this a circular doubly-linked list. 568 * 569 * @param key The initial key for node. 570 */ Node(Object userObject, double key)571 public Node(Object userObject, double key) 572 { 573 this.userObject = userObject; 574 right = this; 575 left = this; 576 this.key = key; 577 } 578 579 /** 580 * Obtain the key for this node. 581 * 582 * @return the key 583 */ getKey()584 public final double getKey() 585 { 586 return key; 587 } 588 589 /** 590 * @return Returns the userObject. 591 */ getUserObject()592 public Object getUserObject() 593 { 594 return userObject; 595 } 596 597 /** 598 * @param userObject The userObject to set. 599 */ setUserObject(Object userObject)600 public void setUserObject(Object userObject) 601 { 602 this.userObject = userObject; 603 } 604 605 } 606 607 } 608