Home | History | Annotate | Download | only in libiberty
      1 /* A Fibonacci heap datatype.
      2    Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
      3    Contributed by Daniel Berlin (dan (at) cgsoftware.com).
      4 
      5 This file is part of GNU CC.
      6 
      7 GNU CC is free software; you can redistribute it and/or modify it
      8 under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2, or (at your option)
     10 any later version.
     11 
     12 GNU CC is distributed in the hope that it will be useful, but
     13 WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15 General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with GNU CC; see the file COPYING.  If not, write to
     19 the Free Software Foundation, 51 Franklin Street - Fifth Floor,
     20 Boston, MA 02110-1301, USA.  */
     21 
     22 #ifdef HAVE_CONFIG_H
     23 #include "config.h"
     24 #endif
     25 #ifdef HAVE_LIMITS_H
     26 #include <limits.h>
     27 #endif
     28 #ifdef HAVE_STDLIB_H
     29 #include <stdlib.h>
     30 #endif
     31 #ifdef HAVE_STRING_H
     32 #include <string.h>
     33 #endif
     34 #include "libiberty.h"
     35 #include "fibheap.h"
     36 
     37 
     38 #define FIBHEAPKEY_MIN	LONG_MIN
     39 
     40 static void fibheap_ins_root (fibheap_t, fibnode_t);
     41 static void fibheap_rem_root (fibheap_t, fibnode_t);
     42 static void fibheap_consolidate (fibheap_t);
     43 static void fibheap_link (fibheap_t, fibnode_t, fibnode_t);
     44 static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t);
     45 static void fibheap_cascading_cut (fibheap_t, fibnode_t);
     46 static fibnode_t fibheap_extr_min_node (fibheap_t);
     47 static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t);
     48 static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t);
     49 static fibnode_t fibnode_new (void);
     50 static void fibnode_insert_after (fibnode_t, fibnode_t);
     51 #define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b)
     52 static fibnode_t fibnode_remove (fibnode_t);
     53 
     54 
     55 /* Create a new fibonacci heap.  */
     57 fibheap_t
     58 fibheap_new (void)
     59 {
     60   return (fibheap_t) xcalloc (1, sizeof (struct fibheap));
     61 }
     62 
     63 /* Create a new fibonacci heap node.  */
     64 static fibnode_t
     65 fibnode_new (void)
     66 {
     67   fibnode_t node;
     68 
     69   node = (fibnode_t) xcalloc (1, sizeof *node);
     70   node->left = node;
     71   node->right = node;
     72 
     73   return node;
     74 }
     75 
     76 static inline int
     77 fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b)
     78 {
     79   if (a->key < b->key)
     80     return -1;
     81   if (a->key > b->key)
     82     return 1;
     83   return 0;
     84 }
     85 
     86 static inline int
     87 fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b)
     88 {
     89   struct fibnode a;
     90 
     91   a.key = key;
     92   a.data = data;
     93 
     94   return fibheap_compare (heap, &a, b);
     95 }
     96 
     97 /* Insert DATA, with priority KEY, into HEAP.  */
     98 fibnode_t
     99 fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data)
    100 {
    101   fibnode_t node;
    102 
    103   /* Create the new node.  */
    104   node = fibnode_new ();
    105 
    106   /* Set the node's data.  */
    107   node->data = data;
    108   node->key = key;
    109 
    110   /* Insert it into the root list.  */
    111   fibheap_ins_root (heap, node);
    112 
    113   /* If their was no minimum, or this key is less than the min,
    114      it's the new min.  */
    115   if (heap->min == NULL || node->key < heap->min->key)
    116     heap->min = node;
    117 
    118   heap->nodes++;
    119 
    120   return node;
    121 }
    122 
    123 /* Return the data of the minimum node (if we know it).  */
    124 void *
    125 fibheap_min (fibheap_t heap)
    126 {
    127   /* If there is no min, we can't easily return it.  */
    128   if (heap->min == NULL)
    129     return NULL;
    130   return heap->min->data;
    131 }
    132 
    133 /* Return the key of the minimum node (if we know it).  */
    134 fibheapkey_t
    135 fibheap_min_key (fibheap_t heap)
    136 {
    137   /* If there is no min, we can't easily return it.  */
    138   if (heap->min == NULL)
    139     return 0;
    140   return heap->min->key;
    141 }
    142 
    143 /* Union HEAPA and HEAPB into a new heap.  */
    144 fibheap_t
    145 fibheap_union (fibheap_t heapa, fibheap_t heapb)
    146 {
    147   fibnode_t a_root, b_root, temp;
    148 
    149   /* If one of the heaps is empty, the union is just the other heap.  */
    150   if ((a_root = heapa->root) == NULL)
    151     {
    152       free (heapa);
    153       return heapb;
    154     }
    155   if ((b_root = heapb->root) == NULL)
    156     {
    157       free (heapb);
    158       return heapa;
    159     }
    160 
    161   /* Merge them to the next nodes on the opposite chain.  */
    162   a_root->left->right = b_root;
    163   b_root->left->right = a_root;
    164   temp = a_root->left;
    165   a_root->left = b_root->left;
    166   b_root->left = temp;
    167   heapa->nodes += heapb->nodes;
    168 
    169   /* And set the new minimum, if it's changed.  */
    170   if (fibheap_compare (heapa, heapb->min, heapa->min) < 0)
    171     heapa->min = heapb->min;
    172 
    173   free (heapb);
    174   return heapa;
    175 }
    176 
    177 /* Extract the data of the minimum node from HEAP.  */
    178 void *
    179 fibheap_extract_min (fibheap_t heap)
    180 {
    181   fibnode_t z;
    182   void *ret = NULL;
    183 
    184   /* If we don't have a min set, it means we have no nodes.  */
    185   if (heap->min != NULL)
    186     {
    187       /* Otherwise, extract the min node, free the node, and return the
    188          node's data.  */
    189       z = fibheap_extr_min_node (heap);
    190       ret = z->data;
    191       free (z);
    192     }
    193 
    194   return ret;
    195 }
    196 
    197 /* Replace both the KEY and the DATA associated with NODE.  */
    198 void *
    199 fibheap_replace_key_data (fibheap_t heap, fibnode_t node,
    200                           fibheapkey_t key, void *data)
    201 {
    202   void *odata;
    203   fibheapkey_t okey;
    204   fibnode_t y;
    205 
    206   /* If we wanted to, we could actually do a real increase by redeleting and
    207      inserting. However, this would require O (log n) time. So just bail out
    208      for now.  */
    209   if (fibheap_comp_data (heap, key, data, node) > 0)
    210     return NULL;
    211 
    212   odata = node->data;
    213   okey = node->key;
    214   node->data = data;
    215   node->key = key;
    216   y = node->parent;
    217 
    218   /* Short-circuit if the key is the same, as we then don't have to
    219      do anything.  Except if we're trying to force the new node to
    220      be the new minimum for delete.  */
    221   if (okey == key && okey != FIBHEAPKEY_MIN)
    222     return odata;
    223 
    224   /* These two compares are specifically <= 0 to make sure that in the case
    225      of equality, a node we replaced the data on, becomes the new min.  This
    226      is needed so that delete's call to extractmin gets the right node.  */
    227   if (y != NULL && fibheap_compare (heap, node, y) <= 0)
    228     {
    229       fibheap_cut (heap, node, y);
    230       fibheap_cascading_cut (heap, y);
    231     }
    232 
    233   if (fibheap_compare (heap, node, heap->min) <= 0)
    234     heap->min = node;
    235 
    236   return odata;
    237 }
    238 
    239 /* Replace the DATA associated with NODE.  */
    240 void *
    241 fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data)
    242 {
    243   return fibheap_replace_key_data (heap, node, node->key, data);
    244 }
    245 
    246 /* Replace the KEY associated with NODE.  */
    247 fibheapkey_t
    248 fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key)
    249 {
    250   int okey = node->key;
    251   fibheap_replace_key_data (heap, node, key, node->data);
    252   return okey;
    253 }
    254 
    255 /* Delete NODE from HEAP.  */
    256 void *
    257 fibheap_delete_node (fibheap_t heap, fibnode_t node)
    258 {
    259   void *ret = node->data;
    260 
    261   /* To perform delete, we just make it the min key, and extract.  */
    262   fibheap_replace_key (heap, node, FIBHEAPKEY_MIN);
    263   if (node != heap->min)
    264     {
    265       fprintf (stderr, "Can't force minimum on fibheap.\n");
    266       abort ();
    267     }
    268   fibheap_extract_min (heap);
    269 
    270   return ret;
    271 }
    272 
    273 /* Delete HEAP.  */
    274 void
    275 fibheap_delete (fibheap_t heap)
    276 {
    277   while (heap->min != NULL)
    278     free (fibheap_extr_min_node (heap));
    279 
    280   free (heap);
    281 }
    282 
    283 /* Determine if HEAP is empty.  */
    284 int
    285 fibheap_empty (fibheap_t heap)
    286 {
    287   return heap->nodes == 0;
    288 }
    289 
    290 /* Extract the minimum node of the heap.  */
    291 static fibnode_t
    292 fibheap_extr_min_node (fibheap_t heap)
    293 {
    294   fibnode_t ret = heap->min;
    295   fibnode_t x, y, orig;
    296 
    297   /* Attach the child list of the minimum node to the root list of the heap.
    298      If there is no child list, we don't do squat.  */
    299   for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y)
    300     {
    301       if (orig == NULL)
    302 	orig = x;
    303       y = x->right;
    304       x->parent = NULL;
    305       fibheap_ins_root (heap, x);
    306     }
    307 
    308   /* Remove the old root.  */
    309   fibheap_rem_root (heap, ret);
    310   heap->nodes--;
    311 
    312   /* If we are left with no nodes, then the min is NULL.  */
    313   if (heap->nodes == 0)
    314     heap->min = NULL;
    315   else
    316     {
    317       /* Otherwise, consolidate to find new minimum, as well as do the reorg
    318          work that needs to be done.  */
    319       heap->min = ret->right;
    320       fibheap_consolidate (heap);
    321     }
    322 
    323   return ret;
    324 }
    325 
    326 /* Insert NODE into the root list of HEAP.  */
    327 static void
    328 fibheap_ins_root (fibheap_t heap, fibnode_t node)
    329 {
    330   /* If the heap is currently empty, the new node becomes the singleton
    331      circular root list.  */
    332   if (heap->root == NULL)
    333     {
    334       heap->root = node;
    335       node->left = node;
    336       node->right = node;
    337       return;
    338     }
    339 
    340   /* Otherwise, insert it in the circular root list between the root
    341      and it's right node.  */
    342   fibnode_insert_after (heap->root, node);
    343 }
    344 
    345 /* Remove NODE from the rootlist of HEAP.  */
    346 static void
    347 fibheap_rem_root (fibheap_t heap, fibnode_t node)
    348 {
    349   if (node->left == node)
    350     heap->root = NULL;
    351   else
    352     heap->root = fibnode_remove (node);
    353 }
    354 
    355 /* Consolidate the heap.  */
    356 static void
    357 fibheap_consolidate (fibheap_t heap)
    358 {
    359   fibnode_t a[1 + 8 * sizeof (long)];
    360   fibnode_t w;
    361   fibnode_t y;
    362   fibnode_t x;
    363   int i;
    364   int d;
    365   int D;
    366 
    367   D = 1 + 8 * sizeof (long);
    368 
    369   memset (a, 0, sizeof (fibnode_t) * D);
    370 
    371   while ((w = heap->root) != NULL)
    372     {
    373       x = w;
    374       fibheap_rem_root (heap, w);
    375       d = x->degree;
    376       while (a[d] != NULL)
    377 	{
    378 	  y = a[d];
    379 	  if (fibheap_compare (heap, x, y) > 0)
    380 	    {
    381 	      fibnode_t temp;
    382 	      temp = x;
    383 	      x = y;
    384 	      y = temp;
    385 	    }
    386 	  fibheap_link (heap, y, x);
    387 	  a[d] = NULL;
    388 	  d++;
    389 	}
    390       a[d] = x;
    391     }
    392   heap->min = NULL;
    393   for (i = 0; i < D; i++)
    394     if (a[i] != NULL)
    395       {
    396 	fibheap_ins_root (heap, a[i]);
    397 	if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0)
    398 	  heap->min = a[i];
    399       }
    400 }
    401 
    402 /* Make NODE a child of PARENT.  */
    403 static void
    404 fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED,
    405               fibnode_t node, fibnode_t parent)
    406 {
    407   if (parent->child == NULL)
    408     parent->child = node;
    409   else
    410     fibnode_insert_before (parent->child, node);
    411   node->parent = parent;
    412   parent->degree++;
    413   node->mark = 0;
    414 }
    415 
    416 /* Remove NODE from PARENT's child list.  */
    417 static void
    418 fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent)
    419 {
    420   fibnode_remove (node);
    421   parent->degree--;
    422   fibheap_ins_root (heap, node);
    423   node->parent = NULL;
    424   node->mark = 0;
    425 }
    426 
    427 static void
    428 fibheap_cascading_cut (fibheap_t heap, fibnode_t y)
    429 {
    430   fibnode_t z;
    431 
    432   while ((z = y->parent) != NULL)
    433     {
    434       if (y->mark == 0)
    435 	{
    436 	  y->mark = 1;
    437 	  return;
    438 	}
    439       else
    440 	{
    441 	  fibheap_cut (heap, y, z);
    442 	  y = z;
    443 	}
    444     }
    445 }
    446 
    447 static void
    448 fibnode_insert_after (fibnode_t a, fibnode_t b)
    449 {
    450   if (a == a->right)
    451     {
    452       a->right = b;
    453       a->left = b;
    454       b->right = a;
    455       b->left = a;
    456     }
    457   else
    458     {
    459       b->right = a->right;
    460       a->right->left = b;
    461       a->right = b;
    462       b->left = a;
    463     }
    464 }
    465 
    466 static fibnode_t
    467 fibnode_remove (fibnode_t node)
    468 {
    469   fibnode_t ret;
    470 
    471   if (node == node->left)
    472     ret = NULL;
    473   else
    474     ret = node->left;
    475 
    476   if (node->parent != NULL && node->parent->child == node)
    477     node->parent->child = ret;
    478 
    479   node->right->left = node->left;
    480   node->left->right = node->right;
    481 
    482   node->parent = NULL;
    483   node->left = node;
    484   node->right = node;
    485 
    486   return ret;
    487 }
    488