198b9484cSchristos /* A Fibonacci heap datatype. 2*5173eb0aSchristos Copyright (C) 1998-2024 Free Software Foundation, Inc. 398b9484cSchristos Contributed by Daniel Berlin (dan@cgsoftware.com). 498b9484cSchristos 598b9484cSchristos This file is part of GNU CC. 698b9484cSchristos 798b9484cSchristos GNU CC is free software; you can redistribute it and/or modify it 898b9484cSchristos under the terms of the GNU General Public License as published by 998b9484cSchristos the Free Software Foundation; either version 2, or (at your option) 1098b9484cSchristos any later version. 1198b9484cSchristos 1298b9484cSchristos GNU CC is distributed in the hope that it will be useful, but 1398b9484cSchristos WITHOUT ANY WARRANTY; without even the implied warranty of 1498b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1598b9484cSchristos General Public License for more details. 1698b9484cSchristos 1798b9484cSchristos You should have received a copy of the GNU General Public License 1898b9484cSchristos along with GNU CC; see the file COPYING. If not, write to 1998b9484cSchristos the Free Software Foundation, 51 Franklin Street - Fifth Floor, 2098b9484cSchristos Boston, MA 02110-1301, USA. */ 2198b9484cSchristos 2298b9484cSchristos #ifdef HAVE_CONFIG_H 2398b9484cSchristos #include "config.h" 2498b9484cSchristos #endif 2598b9484cSchristos #ifdef HAVE_LIMITS_H 2698b9484cSchristos #include <limits.h> 2798b9484cSchristos #endif 2898b9484cSchristos #ifdef HAVE_STDLIB_H 2998b9484cSchristos #include <stdlib.h> 3098b9484cSchristos #endif 3198b9484cSchristos #ifdef HAVE_STRING_H 3298b9484cSchristos #include <string.h> 3398b9484cSchristos #endif 3498b9484cSchristos #include "libiberty.h" 3598b9484cSchristos #include "fibheap.h" 3698b9484cSchristos 3798b9484cSchristos 3898b9484cSchristos #define FIBHEAPKEY_MIN LONG_MIN 3998b9484cSchristos 4098b9484cSchristos static void fibheap_ins_root (fibheap_t, fibnode_t); 4198b9484cSchristos static void fibheap_rem_root (fibheap_t, fibnode_t); 4298b9484cSchristos static void fibheap_consolidate (fibheap_t); 4398b9484cSchristos static void fibheap_link (fibheap_t, fibnode_t, fibnode_t); 4498b9484cSchristos static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t); 4598b9484cSchristos static void fibheap_cascading_cut (fibheap_t, fibnode_t); 4698b9484cSchristos static fibnode_t fibheap_extr_min_node (fibheap_t); 4798b9484cSchristos static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t); 4898b9484cSchristos static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t); 4998b9484cSchristos static fibnode_t fibnode_new (void); 5098b9484cSchristos static void fibnode_insert_after (fibnode_t, fibnode_t); 5198b9484cSchristos #define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b) 5298b9484cSchristos static fibnode_t fibnode_remove (fibnode_t); 5398b9484cSchristos 5498b9484cSchristos 5598b9484cSchristos /* Create a new fibonacci heap. */ 5698b9484cSchristos fibheap_t 5798b9484cSchristos fibheap_new (void) 5898b9484cSchristos { 5998b9484cSchristos return (fibheap_t) xcalloc (1, sizeof (struct fibheap)); 6098b9484cSchristos } 6198b9484cSchristos 6298b9484cSchristos /* Create a new fibonacci heap node. */ 6398b9484cSchristos static fibnode_t 6498b9484cSchristos fibnode_new (void) 6598b9484cSchristos { 6698b9484cSchristos fibnode_t node; 6798b9484cSchristos 6898b9484cSchristos node = (fibnode_t) xcalloc (1, sizeof *node); 6998b9484cSchristos node->left = node; 7098b9484cSchristos node->right = node; 7198b9484cSchristos 7298b9484cSchristos return node; 7398b9484cSchristos } 7498b9484cSchristos 7598b9484cSchristos static inline int 7698b9484cSchristos fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b) 7798b9484cSchristos { 7898b9484cSchristos if (a->key < b->key) 7998b9484cSchristos return -1; 8098b9484cSchristos if (a->key > b->key) 8198b9484cSchristos return 1; 8298b9484cSchristos return 0; 8398b9484cSchristos } 8498b9484cSchristos 8598b9484cSchristos static inline int 8698b9484cSchristos fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b) 8798b9484cSchristos { 8898b9484cSchristos struct fibnode a; 8998b9484cSchristos 9098b9484cSchristos a.key = key; 9198b9484cSchristos a.data = data; 9298b9484cSchristos 9398b9484cSchristos return fibheap_compare (heap, &a, b); 9498b9484cSchristos } 9598b9484cSchristos 9698b9484cSchristos /* Insert DATA, with priority KEY, into HEAP. */ 9798b9484cSchristos fibnode_t 9898b9484cSchristos fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data) 9998b9484cSchristos { 10098b9484cSchristos fibnode_t node; 10198b9484cSchristos 10298b9484cSchristos /* Create the new node. */ 10398b9484cSchristos node = fibnode_new (); 10498b9484cSchristos 10598b9484cSchristos /* Set the node's data. */ 10698b9484cSchristos node->data = data; 10798b9484cSchristos node->key = key; 10898b9484cSchristos 10998b9484cSchristos /* Insert it into the root list. */ 11098b9484cSchristos fibheap_ins_root (heap, node); 11198b9484cSchristos 11298b9484cSchristos /* If their was no minimum, or this key is less than the min, 11398b9484cSchristos it's the new min. */ 11498b9484cSchristos if (heap->min == NULL || node->key < heap->min->key) 11598b9484cSchristos heap->min = node; 11698b9484cSchristos 11798b9484cSchristos heap->nodes++; 11898b9484cSchristos 11998b9484cSchristos return node; 12098b9484cSchristos } 12198b9484cSchristos 12298b9484cSchristos /* Return the data of the minimum node (if we know it). */ 12398b9484cSchristos void * 12498b9484cSchristos fibheap_min (fibheap_t heap) 12598b9484cSchristos { 12698b9484cSchristos /* If there is no min, we can't easily return it. */ 12798b9484cSchristos if (heap->min == NULL) 12898b9484cSchristos return NULL; 12998b9484cSchristos return heap->min->data; 13098b9484cSchristos } 13198b9484cSchristos 13298b9484cSchristos /* Return the key of the minimum node (if we know it). */ 13398b9484cSchristos fibheapkey_t 13498b9484cSchristos fibheap_min_key (fibheap_t heap) 13598b9484cSchristos { 13698b9484cSchristos /* If there is no min, we can't easily return it. */ 13798b9484cSchristos if (heap->min == NULL) 13898b9484cSchristos return 0; 13998b9484cSchristos return heap->min->key; 14098b9484cSchristos } 14198b9484cSchristos 14298b9484cSchristos /* Union HEAPA and HEAPB into a new heap. */ 14398b9484cSchristos fibheap_t 14498b9484cSchristos fibheap_union (fibheap_t heapa, fibheap_t heapb) 14598b9484cSchristos { 14698b9484cSchristos fibnode_t a_root, b_root, temp; 14798b9484cSchristos 14898b9484cSchristos /* If one of the heaps is empty, the union is just the other heap. */ 14998b9484cSchristos if ((a_root = heapa->root) == NULL) 15098b9484cSchristos { 15198b9484cSchristos free (heapa); 15298b9484cSchristos return heapb; 15398b9484cSchristos } 15498b9484cSchristos if ((b_root = heapb->root) == NULL) 15598b9484cSchristos { 15698b9484cSchristos free (heapb); 15798b9484cSchristos return heapa; 15898b9484cSchristos } 15998b9484cSchristos 16098b9484cSchristos /* Merge them to the next nodes on the opposite chain. */ 16198b9484cSchristos a_root->left->right = b_root; 16298b9484cSchristos b_root->left->right = a_root; 16398b9484cSchristos temp = a_root->left; 16498b9484cSchristos a_root->left = b_root->left; 16598b9484cSchristos b_root->left = temp; 16698b9484cSchristos heapa->nodes += heapb->nodes; 16798b9484cSchristos 16898b9484cSchristos /* And set the new minimum, if it's changed. */ 16998b9484cSchristos if (fibheap_compare (heapa, heapb->min, heapa->min) < 0) 17098b9484cSchristos heapa->min = heapb->min; 17198b9484cSchristos 17298b9484cSchristos free (heapb); 17398b9484cSchristos return heapa; 17498b9484cSchristos } 17598b9484cSchristos 17698b9484cSchristos /* Extract the data of the minimum node from HEAP. */ 17798b9484cSchristos void * 17898b9484cSchristos fibheap_extract_min (fibheap_t heap) 17998b9484cSchristos { 18098b9484cSchristos fibnode_t z; 18198b9484cSchristos void *ret = NULL; 18298b9484cSchristos 18398b9484cSchristos /* If we don't have a min set, it means we have no nodes. */ 18498b9484cSchristos if (heap->min != NULL) 18598b9484cSchristos { 18698b9484cSchristos /* Otherwise, extract the min node, free the node, and return the 18798b9484cSchristos node's data. */ 18898b9484cSchristos z = fibheap_extr_min_node (heap); 18998b9484cSchristos ret = z->data; 19098b9484cSchristos free (z); 19198b9484cSchristos } 19298b9484cSchristos 19398b9484cSchristos return ret; 19498b9484cSchristos } 19598b9484cSchristos 19698b9484cSchristos /* Replace both the KEY and the DATA associated with NODE. */ 19798b9484cSchristos void * 19898b9484cSchristos fibheap_replace_key_data (fibheap_t heap, fibnode_t node, 19998b9484cSchristos fibheapkey_t key, void *data) 20098b9484cSchristos { 20198b9484cSchristos void *odata; 20298b9484cSchristos fibheapkey_t okey; 20398b9484cSchristos fibnode_t y; 20498b9484cSchristos 20598b9484cSchristos /* If we wanted to, we could actually do a real increase by redeleting and 20698b9484cSchristos inserting. However, this would require O (log n) time. So just bail out 20798b9484cSchristos for now. */ 20898b9484cSchristos if (fibheap_comp_data (heap, key, data, node) > 0) 20998b9484cSchristos return NULL; 21098b9484cSchristos 21198b9484cSchristos odata = node->data; 21298b9484cSchristos okey = node->key; 21398b9484cSchristos node->data = data; 21498b9484cSchristos node->key = key; 21598b9484cSchristos y = node->parent; 21698b9484cSchristos 21798b9484cSchristos /* Short-circuit if the key is the same, as we then don't have to 21898b9484cSchristos do anything. Except if we're trying to force the new node to 21998b9484cSchristos be the new minimum for delete. */ 22098b9484cSchristos if (okey == key && okey != FIBHEAPKEY_MIN) 22198b9484cSchristos return odata; 22298b9484cSchristos 22398b9484cSchristos /* These two compares are specifically <= 0 to make sure that in the case 22498b9484cSchristos of equality, a node we replaced the data on, becomes the new min. This 22598b9484cSchristos is needed so that delete's call to extractmin gets the right node. */ 22698b9484cSchristos if (y != NULL && fibheap_compare (heap, node, y) <= 0) 22798b9484cSchristos { 22898b9484cSchristos fibheap_cut (heap, node, y); 22998b9484cSchristos fibheap_cascading_cut (heap, y); 23098b9484cSchristos } 23198b9484cSchristos 23298b9484cSchristos if (fibheap_compare (heap, node, heap->min) <= 0) 23398b9484cSchristos heap->min = node; 23498b9484cSchristos 23598b9484cSchristos return odata; 23698b9484cSchristos } 23798b9484cSchristos 23898b9484cSchristos /* Replace the DATA associated with NODE. */ 23998b9484cSchristos void * 24098b9484cSchristos fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data) 24198b9484cSchristos { 24298b9484cSchristos return fibheap_replace_key_data (heap, node, node->key, data); 24398b9484cSchristos } 24498b9484cSchristos 24598b9484cSchristos /* Replace the KEY associated with NODE. */ 24698b9484cSchristos fibheapkey_t 24798b9484cSchristos fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key) 24898b9484cSchristos { 24998b9484cSchristos int okey = node->key; 25098b9484cSchristos fibheap_replace_key_data (heap, node, key, node->data); 25198b9484cSchristos return okey; 25298b9484cSchristos } 25398b9484cSchristos 25498b9484cSchristos /* Delete NODE from HEAP. */ 25598b9484cSchristos void * 25698b9484cSchristos fibheap_delete_node (fibheap_t heap, fibnode_t node) 25798b9484cSchristos { 25898b9484cSchristos void *ret = node->data; 25998b9484cSchristos 26098b9484cSchristos /* To perform delete, we just make it the min key, and extract. */ 26198b9484cSchristos fibheap_replace_key (heap, node, FIBHEAPKEY_MIN); 26298b9484cSchristos if (node != heap->min) 26398b9484cSchristos { 26498b9484cSchristos fprintf (stderr, "Can't force minimum on fibheap.\n"); 26598b9484cSchristos abort (); 26698b9484cSchristos } 26798b9484cSchristos fibheap_extract_min (heap); 26898b9484cSchristos 26998b9484cSchristos return ret; 27098b9484cSchristos } 27198b9484cSchristos 27298b9484cSchristos /* Delete HEAP. */ 27398b9484cSchristos void 27498b9484cSchristos fibheap_delete (fibheap_t heap) 27598b9484cSchristos { 27698b9484cSchristos while (heap->min != NULL) 27798b9484cSchristos free (fibheap_extr_min_node (heap)); 27898b9484cSchristos 27998b9484cSchristos free (heap); 28098b9484cSchristos } 28198b9484cSchristos 28298b9484cSchristos /* Determine if HEAP is empty. */ 28398b9484cSchristos int 28498b9484cSchristos fibheap_empty (fibheap_t heap) 28598b9484cSchristos { 28698b9484cSchristos return heap->nodes == 0; 28798b9484cSchristos } 28898b9484cSchristos 28998b9484cSchristos /* Extract the minimum node of the heap. */ 29098b9484cSchristos static fibnode_t 29198b9484cSchristos fibheap_extr_min_node (fibheap_t heap) 29298b9484cSchristos { 29398b9484cSchristos fibnode_t ret = heap->min; 29498b9484cSchristos fibnode_t x, y, orig; 29598b9484cSchristos 29698b9484cSchristos /* Attach the child list of the minimum node to the root list of the heap. 29798b9484cSchristos If there is no child list, we don't do squat. */ 29898b9484cSchristos for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y) 29998b9484cSchristos { 30098b9484cSchristos if (orig == NULL) 30198b9484cSchristos orig = x; 30298b9484cSchristos y = x->right; 30398b9484cSchristos x->parent = NULL; 30498b9484cSchristos fibheap_ins_root (heap, x); 30598b9484cSchristos } 30698b9484cSchristos 30798b9484cSchristos /* Remove the old root. */ 30898b9484cSchristos fibheap_rem_root (heap, ret); 30998b9484cSchristos heap->nodes--; 31098b9484cSchristos 31198b9484cSchristos /* If we are left with no nodes, then the min is NULL. */ 31298b9484cSchristos if (heap->nodes == 0) 31398b9484cSchristos heap->min = NULL; 31498b9484cSchristos else 31598b9484cSchristos { 31698b9484cSchristos /* Otherwise, consolidate to find new minimum, as well as do the reorg 31798b9484cSchristos work that needs to be done. */ 31898b9484cSchristos heap->min = ret->right; 31998b9484cSchristos fibheap_consolidate (heap); 32098b9484cSchristos } 32198b9484cSchristos 32298b9484cSchristos return ret; 32398b9484cSchristos } 32498b9484cSchristos 32598b9484cSchristos /* Insert NODE into the root list of HEAP. */ 32698b9484cSchristos static void 32798b9484cSchristos fibheap_ins_root (fibheap_t heap, fibnode_t node) 32898b9484cSchristos { 32998b9484cSchristos /* If the heap is currently empty, the new node becomes the singleton 33098b9484cSchristos circular root list. */ 33198b9484cSchristos if (heap->root == NULL) 33298b9484cSchristos { 33398b9484cSchristos heap->root = node; 33498b9484cSchristos node->left = node; 33598b9484cSchristos node->right = node; 33698b9484cSchristos return; 33798b9484cSchristos } 33898b9484cSchristos 33998b9484cSchristos /* Otherwise, insert it in the circular root list between the root 34098b9484cSchristos and it's right node. */ 34198b9484cSchristos fibnode_insert_after (heap->root, node); 34298b9484cSchristos } 34398b9484cSchristos 34498b9484cSchristos /* Remove NODE from the rootlist of HEAP. */ 34598b9484cSchristos static void 34698b9484cSchristos fibheap_rem_root (fibheap_t heap, fibnode_t node) 34798b9484cSchristos { 34898b9484cSchristos if (node->left == node) 34998b9484cSchristos heap->root = NULL; 35098b9484cSchristos else 35198b9484cSchristos heap->root = fibnode_remove (node); 35298b9484cSchristos } 35398b9484cSchristos 35498b9484cSchristos /* Consolidate the heap. */ 35598b9484cSchristos static void 35698b9484cSchristos fibheap_consolidate (fibheap_t heap) 35798b9484cSchristos { 35898b9484cSchristos fibnode_t a[1 + 8 * sizeof (long)]; 35998b9484cSchristos fibnode_t w; 36098b9484cSchristos fibnode_t y; 36198b9484cSchristos fibnode_t x; 36298b9484cSchristos int i; 36398b9484cSchristos int d; 36498b9484cSchristos int D; 36598b9484cSchristos 36698b9484cSchristos D = 1 + 8 * sizeof (long); 36798b9484cSchristos 36898b9484cSchristos memset (a, 0, sizeof (fibnode_t) * D); 36998b9484cSchristos 37098b9484cSchristos while ((w = heap->root) != NULL) 37198b9484cSchristos { 37298b9484cSchristos x = w; 37398b9484cSchristos fibheap_rem_root (heap, w); 37498b9484cSchristos d = x->degree; 37598b9484cSchristos while (a[d] != NULL) 37698b9484cSchristos { 37798b9484cSchristos y = a[d]; 37898b9484cSchristos if (fibheap_compare (heap, x, y) > 0) 37998b9484cSchristos { 38098b9484cSchristos fibnode_t temp; 38198b9484cSchristos temp = x; 38298b9484cSchristos x = y; 38398b9484cSchristos y = temp; 38498b9484cSchristos } 38598b9484cSchristos fibheap_link (heap, y, x); 38698b9484cSchristos a[d] = NULL; 38798b9484cSchristos d++; 38898b9484cSchristos } 38998b9484cSchristos a[d] = x; 39098b9484cSchristos } 39198b9484cSchristos heap->min = NULL; 39298b9484cSchristos for (i = 0; i < D; i++) 39398b9484cSchristos if (a[i] != NULL) 39498b9484cSchristos { 39598b9484cSchristos fibheap_ins_root (heap, a[i]); 39698b9484cSchristos if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0) 39798b9484cSchristos heap->min = a[i]; 39898b9484cSchristos } 39998b9484cSchristos } 40098b9484cSchristos 40198b9484cSchristos /* Make NODE a child of PARENT. */ 40298b9484cSchristos static void 40398b9484cSchristos fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED, 40498b9484cSchristos fibnode_t node, fibnode_t parent) 40598b9484cSchristos { 40698b9484cSchristos if (parent->child == NULL) 40798b9484cSchristos parent->child = node; 40898b9484cSchristos else 40998b9484cSchristos fibnode_insert_before (parent->child, node); 41098b9484cSchristos node->parent = parent; 41198b9484cSchristos parent->degree++; 41298b9484cSchristos node->mark = 0; 41398b9484cSchristos } 41498b9484cSchristos 41598b9484cSchristos /* Remove NODE from PARENT's child list. */ 41698b9484cSchristos static void 41798b9484cSchristos fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent) 41898b9484cSchristos { 41998b9484cSchristos fibnode_remove (node); 42098b9484cSchristos parent->degree--; 42198b9484cSchristos fibheap_ins_root (heap, node); 42298b9484cSchristos node->parent = NULL; 42398b9484cSchristos node->mark = 0; 42498b9484cSchristos } 42598b9484cSchristos 42698b9484cSchristos static void 42798b9484cSchristos fibheap_cascading_cut (fibheap_t heap, fibnode_t y) 42898b9484cSchristos { 42998b9484cSchristos fibnode_t z; 43098b9484cSchristos 43198b9484cSchristos while ((z = y->parent) != NULL) 43298b9484cSchristos { 43398b9484cSchristos if (y->mark == 0) 43498b9484cSchristos { 43598b9484cSchristos y->mark = 1; 43698b9484cSchristos return; 43798b9484cSchristos } 43898b9484cSchristos else 43998b9484cSchristos { 44098b9484cSchristos fibheap_cut (heap, y, z); 44198b9484cSchristos y = z; 44298b9484cSchristos } 44398b9484cSchristos } 44498b9484cSchristos } 44598b9484cSchristos 44698b9484cSchristos static void 44798b9484cSchristos fibnode_insert_after (fibnode_t a, fibnode_t b) 44898b9484cSchristos { 44998b9484cSchristos if (a == a->right) 45098b9484cSchristos { 45198b9484cSchristos a->right = b; 45298b9484cSchristos a->left = b; 45398b9484cSchristos b->right = a; 45498b9484cSchristos b->left = a; 45598b9484cSchristos } 45698b9484cSchristos else 45798b9484cSchristos { 45898b9484cSchristos b->right = a->right; 45998b9484cSchristos a->right->left = b; 46098b9484cSchristos a->right = b; 46198b9484cSchristos b->left = a; 46298b9484cSchristos } 46398b9484cSchristos } 46498b9484cSchristos 46598b9484cSchristos static fibnode_t 46698b9484cSchristos fibnode_remove (fibnode_t node) 46798b9484cSchristos { 46898b9484cSchristos fibnode_t ret; 46998b9484cSchristos 47098b9484cSchristos if (node == node->left) 47198b9484cSchristos ret = NULL; 47298b9484cSchristos else 47398b9484cSchristos ret = node->left; 47498b9484cSchristos 47598b9484cSchristos if (node->parent != NULL && node->parent->child == node) 47698b9484cSchristos node->parent->child = ret; 47798b9484cSchristos 47898b9484cSchristos node->right->left = node->left; 47998b9484cSchristos node->left->right = node->right; 48098b9484cSchristos 48198b9484cSchristos node->parent = NULL; 48298b9484cSchristos node->left = node; 48398b9484cSchristos node->right = node; 48498b9484cSchristos 48598b9484cSchristos return ret; 48698b9484cSchristos } 487