| /* Fibonacci heap for GNU compiler. |
| Copyright (C) 1998-2022 Free Software Foundation, Inc. |
| Contributed by Daniel Berlin (dan@cgsoftware.com). |
| Re-implemented in C++ by Martin Liska <mliska@suse.cz> |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* Fibonacci heaps are somewhat complex, but, there's an article in |
| DDJ that explains them pretty well: |
| |
| http://www.ddj.com/articles/1997/9701/9701o/9701o.htm?topic=algoritms |
| |
| Introduction to algorithms by Corman and Rivest also goes over them. |
| |
| The original paper that introduced them is "Fibonacci heaps and their |
| uses in improved network optimization algorithms" by Tarjan and |
| Fredman (JACM 34(3), July 1987). |
| |
| Amortized and real worst case time for operations: |
| |
| ExtractMin: O(lg n) amortized. O(n) worst case. |
| DecreaseKey: O(1) amortized. O(lg n) worst case. |
| Insert: O(1) amortized. |
| Union: O(1) amortized. */ |
| |
| #ifndef GCC_FIBONACCI_HEAP_H |
| #define GCC_FIBONACCI_HEAP_H |
| |
| /* Forward definition. */ |
| |
| template<class K, class V> |
| class fibonacci_heap; |
| |
| /* Fibonacci heap node class. */ |
| |
| template<class K, class V> |
| class fibonacci_node |
| { |
| typedef fibonacci_node<K,V> fibonacci_node_t; |
| friend class fibonacci_heap<K,V>; |
| |
| public: |
| /* Default constructor. */ |
| fibonacci_node (): m_parent (NULL), m_child (NULL), m_left (this), |
| m_right (this), m_data (NULL), m_degree (0), m_mark (0) |
| { |
| } |
| |
| /* Constructor for a node with given KEY. */ |
| fibonacci_node (K key, V *data = NULL): m_parent (NULL), m_child (NULL), |
| m_left (this), m_right (this), m_key (key), m_data (data), |
| m_degree (0), m_mark (0) |
| { |
| } |
| |
| /* Compare fibonacci node with OTHER node. */ |
| int compare (fibonacci_node_t *other) |
| { |
| if (m_key < other->m_key) |
| return -1; |
| if (m_key > other->m_key) |
| return 1; |
| return 0; |
| } |
| |
| /* Compare the node with a given KEY. */ |
| int compare_data (K key) |
| { |
| return fibonacci_node_t (key).compare (this); |
| } |
| |
| /* Remove fibonacci heap node. */ |
| fibonacci_node_t *remove (); |
| |
| /* Link the node with PARENT. */ |
| void link (fibonacci_node_t *parent); |
| |
| /* Return key associated with the node. */ |
| K get_key () |
| { |
| return m_key; |
| } |
| |
| /* Return data associated with the node. */ |
| V *get_data () |
| { |
| return m_data; |
| } |
| |
| private: |
| /* Put node B after this node. */ |
| void insert_after (fibonacci_node_t *b); |
| |
| /* Insert fibonacci node B after this node. */ |
| void insert_before (fibonacci_node_t *b) |
| { |
| m_left->insert_after (b); |
| } |
| |
| /* Parent node. */ |
| fibonacci_node *m_parent; |
| /* Child node. */ |
| fibonacci_node *m_child; |
| /* Left sibling. */ |
| fibonacci_node *m_left; |
| /* Right node. */ |
| fibonacci_node *m_right; |
| /* Key associated with node. */ |
| K m_key; |
| /* Data associated with node. */ |
| V *m_data; |
| |
| #if defined (__GNUC__) && (!defined (SIZEOF_INT) || SIZEOF_INT < 4) |
| /* Degree of the node. */ |
| __extension__ unsigned long int m_degree : 31; |
| /* Mark of the node. */ |
| __extension__ unsigned long int m_mark : 1; |
| #else |
| /* Degree of the node. */ |
| unsigned int m_degree : 31; |
| /* Mark of the node. */ |
| unsigned int m_mark : 1; |
| #endif |
| }; |
| |
| /* Fibonacci heap class. */ |
| template<class K, class V> |
| class fibonacci_heap |
| { |
| typedef fibonacci_node<K,V> fibonacci_node_t; |
| friend class fibonacci_node<K,V>; |
| |
| public: |
| /* Default constructor. ALLOCATOR is optional and is primarily useful |
| when heaps are going to be merged (in that case they need to be allocated |
| in same alloc pool). */ |
| fibonacci_heap (K global_min_key, pool_allocator *allocator = NULL): |
| m_nodes (0), m_min (NULL), m_root (NULL), |
| m_global_min_key (global_min_key), |
| m_allocator (allocator), m_own_allocator (false) |
| { |
| if (!m_allocator) |
| { |
| m_allocator = new pool_allocator ("Fibonacci heap", |
| sizeof (fibonacci_node_t)); |
| m_own_allocator = true; |
| } |
| } |
| |
| /* Destructor. */ |
| ~fibonacci_heap () |
| { |
| /* Actual memory will be released by the destructor of m_allocator. */ |
| if (need_finalization_p<fibonacci_node_t> () || !m_own_allocator) |
| while (m_min != NULL) |
| { |
| fibonacci_node_t *n = extract_minimum_node (); |
| n->~fibonacci_node_t (); |
| if (!m_own_allocator) |
| m_allocator->remove (n); |
| } |
| if (m_own_allocator) |
| delete m_allocator; |
| } |
| |
| /* Insert new node given by KEY and DATA associated with the key. */ |
| fibonacci_node_t *insert (K key, V *data); |
| |
| /* Return true if no entry is present. */ |
| bool empty () const |
| { |
| return m_nodes == 0; |
| } |
| |
| /* Return the number of nodes. */ |
| size_t nodes () const |
| { |
| return m_nodes; |
| } |
| |
| /* Return minimal key presented in the heap. */ |
| K min_key () const |
| { |
| if (m_min == NULL) |
| gcc_unreachable (); |
| |
| return m_min->m_key; |
| } |
| |
| /* For given NODE, set new KEY value. */ |
| K replace_key (fibonacci_node_t *node, K key) |
| { |
| K okey = node->m_key; |
| |
| replace_key_data (node, key, node->m_data); |
| return okey; |
| } |
| |
| /* For given NODE, decrease value to new KEY. */ |
| K decrease_key (fibonacci_node_t *node, K key) |
| { |
| gcc_assert (key <= node->m_key); |
| return replace_key (node, key); |
| } |
| |
| /* For given NODE, set new KEY and DATA value. */ |
| V *replace_key_data (fibonacci_node_t *node, K key, V *data); |
| |
| /* Extract minimum node in the heap. If RELEASE is specified, |
| memory is released. */ |
| V *extract_min (bool release = true); |
| |
| /* Return value associated with minimum node in the heap. */ |
| V *min () const |
| { |
| if (m_min == NULL) |
| return NULL; |
| |
| return m_min->m_data; |
| } |
| |
| /* Replace data associated with NODE and replace it with DATA. */ |
| V *replace_data (fibonacci_node_t *node, V *data) |
| { |
| return replace_key_data (node, node->m_key, data); |
| } |
| |
| /* Delete NODE in the heap. */ |
| V *delete_node (fibonacci_node_t *node, bool release = true); |
| |
| /* Union the heap with HEAPB. */ |
| fibonacci_heap *union_with (fibonacci_heap *heapb); |
| |
| private: |
| /* Insert new NODE given by KEY and DATA associated with the key. */ |
| fibonacci_node_t *insert (fibonacci_node_t *node, K key, V *data); |
| |
| /* Insert new NODE that has already filled key and value. */ |
| fibonacci_node_t *insert_node (fibonacci_node_t *node); |
| |
| /* Insert it into the root list. */ |
| void insert_root (fibonacci_node_t *node); |
| |
| /* Remove NODE from PARENT's child list. */ |
| void cut (fibonacci_node_t *node, fibonacci_node_t *parent); |
| |
| /* Process cut of node Y and do it recursivelly. */ |
| void cascading_cut (fibonacci_node_t *y); |
| |
| /* Extract minimum node from the heap. */ |
| fibonacci_node_t * extract_minimum_node (); |
| |
| /* Remove root NODE from the heap. */ |
| void remove_root (fibonacci_node_t *node); |
| |
| /* Consolidate heap. */ |
| void consolidate (); |
| |
| /* Number of nodes. */ |
| size_t m_nodes; |
| /* Minimum node of the heap. */ |
| fibonacci_node_t *m_min; |
| /* Root node of the heap. */ |
| fibonacci_node_t *m_root; |
| /* Global minimum given in the heap construction. */ |
| K m_global_min_key; |
| |
| /* Allocator used to hold nodes. */ |
| pool_allocator *m_allocator; |
| /* True if alocator is owned by the current heap only. */ |
| bool m_own_allocator; |
| }; |
| |
| /* Remove fibonacci heap node. */ |
| |
| template<class K, class V> |
| fibonacci_node<K,V> * |
| fibonacci_node<K,V>::remove () |
| { |
| fibonacci_node<K,V> *ret; |
| |
| if (this == m_left) |
| ret = NULL; |
| else |
| ret = m_left; |
| |
| if (m_parent != NULL && m_parent->m_child == this) |
| m_parent->m_child = ret; |
| |
| m_right->m_left = m_left; |
| m_left->m_right = m_right; |
| |
| m_parent = NULL; |
| m_left = this; |
| m_right = this; |
| |
| return ret; |
| } |
| |
| /* Link the node with PARENT. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_node<K,V>::link (fibonacci_node<K,V> *parent) |
| { |
| if (parent->m_child == NULL) |
| parent->m_child = this; |
| else |
| parent->m_child->insert_before (this); |
| m_parent = parent; |
| parent->m_degree++; |
| m_mark = 0; |
| } |
| |
| /* Put node B after this node. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_node<K,V>::insert_after (fibonacci_node<K,V> *b) |
| { |
| fibonacci_node<K,V> *a = this; |
| |
| if (a == a->m_right) |
| { |
| a->m_right = b; |
| a->m_left = b; |
| b->m_right = a; |
| b->m_left = a; |
| } |
| else |
| { |
| b->m_right = a->m_right; |
| a->m_right->m_left = b; |
| a->m_right = b; |
| b->m_left = a; |
| } |
| } |
| |
| /* Insert new node given by KEY and DATA associated with the key. */ |
| |
| template<class K, class V> |
| fibonacci_node<K,V>* |
| fibonacci_heap<K,V>::insert (K key, V *data) |
| { |
| /* Create the new node. */ |
| fibonacci_node<K,V> *node = new (m_allocator->allocate ()) |
| fibonacci_node_t (key, data); |
| |
| return insert_node (node); |
| } |
| |
| /* Insert new NODE given by DATA associated with the key. */ |
| |
| template<class K, class V> |
| fibonacci_node<K,V>* |
| fibonacci_heap<K,V>::insert (fibonacci_node_t *node, K key, V *data) |
| { |
| /* Set the node's data. */ |
| node->m_data = data; |
| node->m_key = key; |
| |
| return insert_node (node); |
| } |
| |
| /* Insert new NODE that has already filled key and value. */ |
| |
| template<class K, class V> |
| fibonacci_node<K,V>* |
| fibonacci_heap<K,V>::insert_node (fibonacci_node_t *node) |
| { |
| /* Insert it into the root list. */ |
| insert_root (node); |
| |
| /* If their was no minimum, or this key is less than the min, |
| it's the new min. */ |
| if (m_min == NULL || node->m_key < m_min->m_key) |
| m_min = node; |
| |
| m_nodes++; |
| |
| return node; |
| } |
| |
| /* For given NODE, set new KEY and DATA value. */ |
| |
| template<class K, class V> |
| V* |
| fibonacci_heap<K,V>::replace_key_data (fibonacci_node<K,V> *node, K key, |
| V *data) |
| { |
| K okey; |
| fibonacci_node<K,V> *y; |
| V *odata = node->m_data; |
| |
| /* If we wanted to, we do a real increase by redeleting and |
| inserting. */ |
| if (node->compare_data (key) > 0) |
| { |
| delete_node (node, false); |
| |
| node = new (node) fibonacci_node_t (); |
| insert (node, key, data); |
| |
| return odata; |
| } |
| |
| okey = node->m_key; |
| node->m_data = data; |
| node->m_key = key; |
| y = node->m_parent; |
| |
| /* Short-circuit if the key is the same, as we then don't have to |
| do anything. Except if we're trying to force the new node to |
| be the new minimum for delete. */ |
| if (okey == key && okey != m_global_min_key) |
| return odata; |
| |
| /* These two compares are specifically <= 0 to make sure that in the case |
| of equality, a node we replaced the data on, becomes the new min. This |
| is needed so that delete's call to extractmin gets the right node. */ |
| if (y != NULL && node->compare (y) <= 0) |
| { |
| cut (node, y); |
| cascading_cut (y); |
| } |
| |
| if (node->compare (m_min) <= 0) |
| m_min = node; |
| |
| return odata; |
| } |
| |
| /* Extract minimum node in the heap. Delete fibonacci node if RELEASE |
| is true. */ |
| |
| template<class K, class V> |
| V* |
| fibonacci_heap<K,V>::extract_min (bool release) |
| { |
| fibonacci_node<K,V> *z; |
| V *ret = NULL; |
| |
| /* If we don't have a min set, it means we have no nodes. */ |
| if (m_min != NULL) |
| { |
| /* Otherwise, extract the min node, free the node, and return the |
| node's data. */ |
| z = extract_minimum_node (); |
| ret = z->m_data; |
| |
| if (release) |
| { |
| z->~fibonacci_node_t (); |
| m_allocator->remove (z); |
| } |
| } |
| |
| return ret; |
| } |
| |
| /* Delete NODE in the heap, if RELEASE is specified memory is released. */ |
| |
| template<class K, class V> |
| V* |
| fibonacci_heap<K,V>::delete_node (fibonacci_node<K,V> *node, bool release) |
| { |
| V *ret = node->m_data; |
| |
| /* To perform delete, we just make it the min key, and extract. */ |
| replace_key (node, m_global_min_key); |
| if (node != m_min) |
| { |
| fprintf (stderr, "Can't force minimum on fibheap.\n"); |
| abort (); |
| } |
| extract_min (release); |
| |
| return ret; |
| } |
| |
| /* Union the heap with HEAPB. One of the heaps is going to be deleted. */ |
| |
| template<class K, class V> |
| fibonacci_heap<K,V>* |
| fibonacci_heap<K,V>::union_with (fibonacci_heap<K,V> *heapb) |
| { |
| fibonacci_heap<K,V> *heapa = this; |
| |
| fibonacci_node<K,V> *a_root, *b_root; |
| |
| /* Both heaps must share allocator. */ |
| gcc_checking_assert (m_allocator == heapb->m_allocator); |
| |
| /* If one of the heaps is empty, the union is just the other heap. */ |
| if ((a_root = heapa->m_root) == NULL) |
| { |
| delete (heapa); |
| return heapb; |
| } |
| if ((b_root = heapb->m_root) == NULL) |
| { |
| delete (heapb); |
| return heapa; |
| } |
| |
| /* Merge them to the next nodes on the opposite chain. */ |
| a_root->m_left->m_right = b_root; |
| b_root->m_left->m_right = a_root; |
| std::swap (a_root->m_left, b_root->m_left); |
| heapa->m_nodes += heapb->m_nodes; |
| |
| /* And set the new minimum, if it's changed. */ |
| if (heapb->m_min->compare (heapa->m_min) < 0) |
| heapa->m_min = heapb->m_min; |
| |
| /* Set m_min to NULL to not to delete live fibonacci nodes. */ |
| heapb->m_min = NULL; |
| delete (heapb); |
| |
| return heapa; |
| } |
| |
| /* Insert it into the root list. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_heap<K,V>::insert_root (fibonacci_node_t *node) |
| { |
| /* If the heap is currently empty, the new node becomes the singleton |
| circular root list. */ |
| if (m_root == NULL) |
| { |
| m_root = node; |
| node->m_left = node; |
| node->m_right = node; |
| return; |
| } |
| |
| /* Otherwise, insert it in the circular root list between the root |
| and it's right node. */ |
| m_root->insert_after (node); |
| } |
| |
| /* Remove NODE from PARENT's child list. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_heap<K,V>::cut (fibonacci_node<K,V> *node, |
| fibonacci_node<K,V> *parent) |
| { |
| node->remove (); |
| parent->m_degree--; |
| insert_root (node); |
| node->m_parent = NULL; |
| node->m_mark = 0; |
| } |
| |
| /* Process cut of node Y and do it recursivelly. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_heap<K,V>::cascading_cut (fibonacci_node<K,V> *y) |
| { |
| fibonacci_node<K,V> *z; |
| |
| while ((z = y->m_parent) != NULL) |
| { |
| if (y->m_mark == 0) |
| { |
| y->m_mark = 1; |
| return; |
| } |
| else |
| { |
| cut (y, z); |
| y = z; |
| } |
| } |
| } |
| |
| /* Extract minimum node from the heap. */ |
| |
| template<class K, class V> |
| fibonacci_node<K,V>* |
| fibonacci_heap<K,V>::extract_minimum_node () |
| { |
| fibonacci_node<K,V> *ret = m_min; |
| fibonacci_node<K,V> *x, *y, *orig; |
| |
| /* Attach the child list of the minimum node to the root list of the heap. |
| If there is no child list, we don't do squat. */ |
| for (x = ret->m_child, orig = NULL; x != orig && x != NULL; x = y) |
| { |
| if (orig == NULL) |
| orig = x; |
| y = x->m_right; |
| x->m_parent = NULL; |
| insert_root (x); |
| } |
| |
| /* Remove the old root. */ |
| remove_root (ret); |
| m_nodes--; |
| |
| /* If we are left with no nodes, then the min is NULL. */ |
| if (m_nodes == 0) |
| m_min = NULL; |
| else |
| { |
| /* Otherwise, consolidate to find new minimum, as well as do the reorg |
| work that needs to be done. */ |
| m_min = ret->m_right; |
| consolidate (); |
| } |
| |
| return ret; |
| } |
| |
| /* Remove root NODE from the heap. */ |
| |
| template<class K, class V> |
| void |
| fibonacci_heap<K,V>::remove_root (fibonacci_node<K,V> *node) |
| { |
| if (node->m_left == node) |
| m_root = NULL; |
| else |
| m_root = node->remove (); |
| } |
| |
| /* Consolidate heap. */ |
| |
| template<class K, class V> |
| void fibonacci_heap<K,V>::consolidate () |
| { |
| const int D = 1 + 8 * sizeof (long); |
| fibonacci_node<K,V> *a[D]; |
| fibonacci_node<K,V> *w, *x, *y; |
| int i, d; |
| |
| memset (a, 0, sizeof (a)); |
| |
| while ((w = m_root) != NULL) |
| { |
| x = w; |
| remove_root (w); |
| d = x->m_degree; |
| gcc_checking_assert (d < D); |
| while (a[d] != NULL) |
| { |
| y = a[d]; |
| if (x->compare (y) > 0) |
| std::swap (x, y); |
| y->link (x); |
| a[d] = NULL; |
| d++; |
| } |
| a[d] = x; |
| } |
| m_min = NULL; |
| for (i = 0; i < D; i++) |
| if (a[i] != NULL) |
| { |
| insert_root (a[i]); |
| if (m_min == NULL || a[i]->compare (m_min) < 0) |
| m_min = a[i]; |
| } |
| } |
| |
| #endif // GCC_FIBONACCI_HEAP_H |