1 /* Fibonacci heap for GNU compiler. 2 Copyright (C) 1998-2020 Free Software Foundation, Inc. 3 Contributed by Daniel Berlin (dan@cgsoftware.com). 4 Re-implemented in C++ by Martin Liska <mliska@suse.cz> 5 6 This file is part of GCC. 7 8 GCC is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free 10 Software Foundation; either version 3, or (at your option) any later 11 version. 12 13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GCC; see the file COPYING3. If not see 20 <http://www.gnu.org/licenses/>. */ 21 22 /* Fibonacci heaps are somewhat complex, but, there's an article in 23 DDJ that explains them pretty well: 24 25 http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms 26 27 Introduction to algorithms by Corman and Rivest also goes over them. 28 29 The original paper that introduced them is "Fibonacci heaps and their 30 uses in improved network optimization algorithms" by Tarjan and 31 Fredman (JACM 34(3), July 1987). 32 33 Amortized and real worst case time for operations: 34 35 ExtractMin: O(lg n) amortized. O(n) worst case. 36 DecreaseKey: O(1) amortized. O(lg n) worst case. 37 Insert: O(1) amortized. 38 Union: O(1) amortized. */ 39 40 #ifndef GCC_FIBONACCI_HEAP_H 41 #define GCC_FIBONACCI_HEAP_H 42 43 /* Forward definition. */ 44 45 template<class K, class V> 46 class fibonacci_heap; 47 48 /* Fibonacci heap node class. */ 49 50 template<class K, class V> 51 class fibonacci_node 52 { 53 typedef fibonacci_node<K,V> fibonacci_node_t; 54 friend class fibonacci_heap<K,V>; 55 56 public: 57 /* Default constructor. */ 58 fibonacci_node (): m_parent (NULL), m_child (NULL), m_left (this), 59 m_right (this), m_data (NULL), m_degree (0), m_mark (0) 60 { 61 } 62 63 /* Constructor for a node with given KEY. */ 64 fibonacci_node (K key, V *data = NULL): m_parent (NULL), m_child (NULL), 65 m_left (this), m_right (this), m_key (key), m_data (data), 66 m_degree (0), m_mark (0) 67 { 68 } 69 70 /* Compare fibonacci node with OTHER node. */ 71 int compare (fibonacci_node_t *other) 72 { 73 if (m_key < other->m_key) 74 return -1; 75 if (m_key > other->m_key) 76 return 1; 77 return 0; 78 } 79 80 /* Compare the node with a given KEY. */ 81 int compare_data (K key) 82 { 83 return fibonacci_node_t (key).compare (this); 84 } 85 86 /* Remove fibonacci heap node. */ 87 fibonacci_node_t *remove (); 88 89 /* Link the node with PARENT. */ 90 void link (fibonacci_node_t *parent); 91 92 /* Return key associated with the node. */ 93 K get_key () 94 { 95 return m_key; 96 } 97 98 /* Return data associated with the node. */ 99 V *get_data () 100 { 101 return m_data; 102 } 103 104 private: 105 /* Put node B after this node. */ 106 void insert_after (fibonacci_node_t *b); 107 108 /* Insert fibonacci node B after this node. */ 109 void insert_before (fibonacci_node_t *b) 110 { 111 m_left->insert_after (b); 112 } 113 114 /* Parent node. */ 115 fibonacci_node *m_parent; 116 /* Child node. */ 117 fibonacci_node *m_child; 118 /* Left sibling. */ 119 fibonacci_node *m_left; 120 /* Right node. */ 121 fibonacci_node *m_right; 122 /* Key associated with node. */ 123 K m_key; 124 /* Data associated with node. */ 125 V *m_data; 126 127 #if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4) 128 /* Degree of the node. */ 129 __extension__ unsigned long int m_degree : 31; 130 /* Mark of the node. */ 131 __extension__ unsigned long int m_mark : 1; 132 #else 133 /* Degree of the node. */ 134 unsigned int m_degree : 31; 135 /* Mark of the node. */ 136 unsigned int m_mark : 1; 137 #endif 138 }; 139 140 /* Fibonacci heap class. */ 141 template<class K, class V> 142 class fibonacci_heap 143 { 144 typedef fibonacci_node<K,V> fibonacci_node_t; 145 friend class fibonacci_node<K,V>; 146 147 public: 148 /* Default constructor. ALLOCATOR is optional and is primarily useful 149 when heaps are going to be merged (in that case they need to be allocated 150 in same alloc pool). */ 151 fibonacci_heap (K global_min_key, pool_allocator *allocator = NULL): 152 m_nodes (0), m_min (NULL), m_root (NULL), 153 m_global_min_key (global_min_key), 154 m_allocator (allocator), m_own_allocator (false) 155 { 156 if (!m_allocator) 157 { 158 m_allocator = new pool_allocator ("Fibonacci heap", 159 sizeof (fibonacci_node_t)); 160 m_own_allocator = true; 161 } 162 } 163 164 /* Destructor. */ 165 ~fibonacci_heap () 166 { 167 /* Actual memory will be released by the destructor of m_allocator. */ 168 if (need_finalization_p<fibonacci_node_t> () || !m_own_allocator) 169 while (m_min != NULL) 170 { 171 fibonacci_node_t *n = extract_minimum_node (); 172 n->~fibonacci_node_t (); 173 if (!m_own_allocator) 174 m_allocator->remove (n); 175 } 176 if (m_own_allocator) 177 delete m_allocator; 178 } 179 180 /* Insert new node given by KEY and DATA associated with the key. */ 181 fibonacci_node_t *insert (K key, V *data); 182 183 /* Return true if no entry is present. */ 184 bool empty () const 185 { 186 return m_nodes == 0; 187 } 188 189 /* Return the number of nodes. */ 190 size_t nodes () const 191 { 192 return m_nodes; 193 } 194 195 /* Return minimal key presented in the heap. */ 196 K min_key () const 197 { 198 if (m_min == NULL) 199 gcc_unreachable (); 200 201 return m_min->m_key; 202 } 203 204 /* For given NODE, set new KEY value. */ 205 K replace_key (fibonacci_node_t *node, K key) 206 { 207 K okey = node->m_key; 208 209 replace_key_data (node, key, node->m_data); 210 return okey; 211 } 212 213 /* For given NODE, decrease value to new KEY. */ 214 K decrease_key (fibonacci_node_t *node, K key) 215 { 216 gcc_assert (key <= node->m_key); 217 return replace_key (node, key); 218 } 219 220 /* For given NODE, set new KEY and DATA value. */ 221 V *replace_key_data (fibonacci_node_t *node, K key, V *data); 222 223 /* Extract minimum node in the heap. If RELEASE is specified, 224 memory is released. */ 225 V *extract_min (bool release = true); 226 227 /* Return value associated with minimum node in the heap. */ 228 V *min () const 229 { 230 if (m_min == NULL) 231 return NULL; 232 233 return m_min->m_data; 234 } 235 236 /* Replace data associated with NODE and replace it with DATA. */ 237 V *replace_data (fibonacci_node_t *node, V *data) 238 { 239 return replace_key_data (node, node->m_key, data); 240 } 241 242 /* Delete NODE in the heap. */ 243 V *delete_node (fibonacci_node_t *node, bool release = true); 244 245 /* Union the heap with HEAPB. */ 246 fibonacci_heap *union_with (fibonacci_heap *heapb); 247 248 private: 249 /* Insert new NODE given by KEY and DATA associated with the key. */ 250 fibonacci_node_t *insert (fibonacci_node_t *node, K key, V *data); 251 252 /* Insert new NODE that has already filled key and value. */ 253 fibonacci_node_t *insert_node (fibonacci_node_t *node); 254 255 /* Insert it into the root list. */ 256 void insert_root (fibonacci_node_t *node); 257 258 /* Remove NODE from PARENT's child list. */ 259 void cut (fibonacci_node_t *node, fibonacci_node_t *parent); 260 261 /* Process cut of node Y and do it recursivelly. */ 262 void cascading_cut (fibonacci_node_t *y); 263 264 /* Extract minimum node from the heap. */ 265 fibonacci_node_t * extract_minimum_node (); 266 267 /* Remove root NODE from the heap. */ 268 void remove_root (fibonacci_node_t *node); 269 270 /* Consolidate heap. */ 271 void consolidate (); 272 273 /* Number of nodes. */ 274 size_t m_nodes; 275 /* Minimum node of the heap. */ 276 fibonacci_node_t *m_min; 277 /* Root node of the heap. */ 278 fibonacci_node_t *m_root; 279 /* Global minimum given in the heap construction. */ 280 K m_global_min_key; 281 282 /* Allocator used to hold nodes. */ 283 pool_allocator *m_allocator; 284 /* True if alocator is owned by the current heap only. */ 285 bool m_own_allocator; 286 }; 287 288 /* Remove fibonacci heap node. */ 289 290 template<class K, class V> 291 fibonacci_node<K,V> * 292 fibonacci_node<K,V>::remove () 293 { 294 fibonacci_node<K,V> *ret; 295 296 if (this == m_left) 297 ret = NULL; 298 else 299 ret = m_left; 300 301 if (m_parent != NULL && m_parent->m_child == this) 302 m_parent->m_child = ret; 303 304 m_right->m_left = m_left; 305 m_left->m_right = m_right; 306 307 m_parent = NULL; 308 m_left = this; 309 m_right = this; 310 311 return ret; 312 } 313 314 /* Link the node with PARENT. */ 315 316 template<class K, class V> 317 void 318 fibonacci_node<K,V>::link (fibonacci_node<K,V> *parent) 319 { 320 if (parent->m_child == NULL) 321 parent->m_child = this; 322 else 323 parent->m_child->insert_before (this); 324 m_parent = parent; 325 parent->m_degree++; 326 m_mark = 0; 327 } 328 329 /* Put node B after this node. */ 330 331 template<class K, class V> 332 void 333 fibonacci_node<K,V>::insert_after (fibonacci_node<K,V> *b) 334 { 335 fibonacci_node<K,V> *a = this; 336 337 if (a == a->m_right) 338 { 339 a->m_right = b; 340 a->m_left = b; 341 b->m_right = a; 342 b->m_left = a; 343 } 344 else 345 { 346 b->m_right = a->m_right; 347 a->m_right->m_left = b; 348 a->m_right = b; 349 b->m_left = a; 350 } 351 } 352 353 /* Insert new node given by KEY and DATA associated with the key. */ 354 355 template<class K, class V> 356 fibonacci_node<K,V>* 357 fibonacci_heap<K,V>::insert (K key, V *data) 358 { 359 /* Create the new node. */ 360 fibonacci_node<K,V> *node = new (m_allocator->allocate ()) 361 fibonacci_node_t (key, data); 362 363 return insert_node (node); 364 } 365 366 /* Insert new NODE given by DATA associated with the key. */ 367 368 template<class K, class V> 369 fibonacci_node<K,V>* 370 fibonacci_heap<K,V>::insert (fibonacci_node_t *node, K key, V *data) 371 { 372 /* Set the node's data. */ 373 node->m_data = data; 374 node->m_key = key; 375 376 return insert_node (node); 377 } 378 379 /* Insert new NODE that has already filled key and value. */ 380 381 template<class K, class V> 382 fibonacci_node<K,V>* 383 fibonacci_heap<K,V>::insert_node (fibonacci_node_t *node) 384 { 385 /* Insert it into the root list. */ 386 insert_root (node); 387 388 /* If their was no minimum, or this key is less than the min, 389 it's the new min. */ 390 if (m_min == NULL || node->m_key < m_min->m_key) 391 m_min = node; 392 393 m_nodes++; 394 395 return node; 396 } 397 398 /* For given NODE, set new KEY and DATA value. */ 399 400 template<class K, class V> 401 V* 402 fibonacci_heap<K,V>::replace_key_data (fibonacci_node<K,V> *node, K key, 403 V *data) 404 { 405 K okey; 406 fibonacci_node<K,V> *y; 407 V *odata = node->m_data; 408 409 /* If we wanted to, we do a real increase by redeleting and 410 inserting. */ 411 if (node->compare_data (key) > 0) 412 { 413 delete_node (node, false); 414 415 node = new (node) fibonacci_node_t (); 416 insert (node, key, data); 417 418 return odata; 419 } 420 421 okey = node->m_key; 422 node->m_data = data; 423 node->m_key = key; 424 y = node->m_parent; 425 426 /* Short-circuit if the key is the same, as we then don't have to 427 do anything. Except if we're trying to force the new node to 428 be the new minimum for delete. */ 429 if (okey == key && okey != m_global_min_key) 430 return odata; 431 432 /* These two compares are specifically <= 0 to make sure that in the case 433 of equality, a node we replaced the data on, becomes the new min. This 434 is needed so that delete's call to extractmin gets the right node. */ 435 if (y != NULL && node->compare (y) <= 0) 436 { 437 cut (node, y); 438 cascading_cut (y); 439 } 440 441 if (node->compare (m_min) <= 0) 442 m_min = node; 443 444 return odata; 445 } 446 447 /* Extract minimum node in the heap. Delete fibonacci node if RELEASE 448 is true. */ 449 450 template<class K, class V> 451 V* 452 fibonacci_heap<K,V>::extract_min (bool release) 453 { 454 fibonacci_node<K,V> *z; 455 V *ret = NULL; 456 457 /* If we don't have a min set, it means we have no nodes. */ 458 if (m_min != NULL) 459 { 460 /* Otherwise, extract the min node, free the node, and return the 461 node's data. */ 462 z = extract_minimum_node (); 463 ret = z->m_data; 464 465 if (release) 466 { 467 z->~fibonacci_node_t (); 468 m_allocator->remove (z); 469 } 470 } 471 472 return ret; 473 } 474 475 /* Delete NODE in the heap, if RELEASE is specified memory is released. */ 476 477 template<class K, class V> 478 V* 479 fibonacci_heap<K,V>::delete_node (fibonacci_node<K,V> *node, bool release) 480 { 481 V *ret = node->m_data; 482 483 /* To perform delete, we just make it the min key, and extract. */ 484 replace_key (node, m_global_min_key); 485 if (node != m_min) 486 { 487 fprintf (stderr, "Can't force minimum on fibheap.\n"); 488 abort (); 489 } 490 extract_min (release); 491 492 return ret; 493 } 494 495 /* Union the heap with HEAPB. One of the heaps is going to be deleted. */ 496 497 template<class K, class V> 498 fibonacci_heap<K,V>* 499 fibonacci_heap<K,V>::union_with (fibonacci_heap<K,V> *heapb) 500 { 501 fibonacci_heap<K,V> *heapa = this; 502 503 fibonacci_node<K,V> *a_root, *b_root; 504 505 /* Both heaps must share allocator. */ 506 gcc_checking_assert (m_allocator == heapb->m_allocator); 507 508 /* If one of the heaps is empty, the union is just the other heap. */ 509 if ((a_root = heapa->m_root) == NULL) 510 { 511 delete (heapa); 512 return heapb; 513 } 514 if ((b_root = heapb->m_root) == NULL) 515 { 516 delete (heapb); 517 return heapa; 518 } 519 520 /* Merge them to the next nodes on the opposite chain. */ 521 a_root->m_left->m_right = b_root; 522 b_root->m_left->m_right = a_root; 523 std::swap (a_root->m_left, b_root->m_left); 524 heapa->m_nodes += heapb->m_nodes; 525 526 /* And set the new minimum, if it's changed. */ 527 if (heapb->m_min->compare (heapa->m_min) < 0) 528 heapa->m_min = heapb->m_min; 529 530 /* Set m_min to NULL to not to delete live fibonacci nodes. */ 531 heapb->m_min = NULL; 532 delete (heapb); 533 534 return heapa; 535 } 536 537 /* Insert it into the root list. */ 538 539 template<class K, class V> 540 void 541 fibonacci_heap<K,V>::insert_root (fibonacci_node_t *node) 542 { 543 /* If the heap is currently empty, the new node becomes the singleton 544 circular root list. */ 545 if (m_root == NULL) 546 { 547 m_root = node; 548 node->m_left = node; 549 node->m_right = node; 550 return; 551 } 552 553 /* Otherwise, insert it in the circular root list between the root 554 and it's right node. */ 555 m_root->insert_after (node); 556 } 557 558 /* Remove NODE from PARENT's child list. */ 559 560 template<class K, class V> 561 void 562 fibonacci_heap<K,V>::cut (fibonacci_node<K,V> *node, 563 fibonacci_node<K,V> *parent) 564 { 565 node->remove (); 566 parent->m_degree--; 567 insert_root (node); 568 node->m_parent = NULL; 569 node->m_mark = 0; 570 } 571 572 /* Process cut of node Y and do it recursivelly. */ 573 574 template<class K, class V> 575 void 576 fibonacci_heap<K,V>::cascading_cut (fibonacci_node<K,V> *y) 577 { 578 fibonacci_node<K,V> *z; 579 580 while ((z = y->m_parent) != NULL) 581 { 582 if (y->m_mark == 0) 583 { 584 y->m_mark = 1; 585 return; 586 } 587 else 588 { 589 cut (y, z); 590 y = z; 591 } 592 } 593 } 594 595 /* Extract minimum node from the heap. */ 596 597 template<class K, class V> 598 fibonacci_node<K,V>* 599 fibonacci_heap<K,V>::extract_minimum_node () 600 { 601 fibonacci_node<K,V> *ret = m_min; 602 fibonacci_node<K,V> *x, *y, *orig; 603 604 /* Attach the child list of the minimum node to the root list of the heap. 605 If there is no child list, we don't do squat. */ 606 for (x = ret->m_child, orig = NULL; x != orig && x != NULL; x = y) 607 { 608 if (orig == NULL) 609 orig = x; 610 y = x->m_right; 611 x->m_parent = NULL; 612 insert_root (x); 613 } 614 615 /* Remove the old root. */ 616 remove_root (ret); 617 m_nodes--; 618 619 /* If we are left with no nodes, then the min is NULL. */ 620 if (m_nodes == 0) 621 m_min = NULL; 622 else 623 { 624 /* Otherwise, consolidate to find new minimum, as well as do the reorg 625 work that needs to be done. */ 626 m_min = ret->m_right; 627 consolidate (); 628 } 629 630 return ret; 631 } 632 633 /* Remove root NODE from the heap. */ 634 635 template<class K, class V> 636 void 637 fibonacci_heap<K,V>::remove_root (fibonacci_node<K,V> *node) 638 { 639 if (node->m_left == node) 640 m_root = NULL; 641 else 642 m_root = node->remove (); 643 } 644 645 /* Consolidate heap. */ 646 647 template<class K, class V> 648 void fibonacci_heap<K,V>::consolidate () 649 { 650 const int D = 1 + 8 * sizeof (long); 651 fibonacci_node<K,V> *a[D]; 652 fibonacci_node<K,V> *w, *x, *y; 653 int i, d; 654 655 memset (a, 0, sizeof (a)); 656 657 while ((w = m_root) != NULL) 658 { 659 x = w; 660 remove_root (w); 661 d = x->m_degree; 662 gcc_checking_assert (d < D); 663 while (a[d] != NULL) 664 { 665 y = a[d]; 666 if (x->compare (y) > 0) 667 std::swap (x, y); 668 y->link (x); 669 a[d] = NULL; 670 d++; 671 } 672 a[d] = x; 673 } 674 m_min = NULL; 675 for (i = 0; i < D; i++) 676 if (a[i] != NULL) 677 { 678 insert_root (a[i]); 679 if (m_min == NULL || a[i]->compare (m_min) < 0) 680 m_min = a[i]; 681 } 682 } 683 684 #endif // GCC_FIBONACCI_HEAP_H 685