xref: /netbsd-src/external/gpl3/gdb/dist/libiberty/fibheap.c (revision 5173eb0a33e5d83890ba976253e703be4c92557c)
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