fibheap.c 10.8 KB
Newer Older
Daniel Berlin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/* A Fibonacci heap datatype.
   Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
   Contributed by Daniel Berlin (dan@cgsoftware.com).
   
This file is part of GNU CC.
   
GNU CC 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 2, or (at your option)
any later version.

GNU CC 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 GNU CC; see the file COPYING.  If not, write to
19 20
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.  */
Daniel Berlin committed
21

22 23 24 25
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_LIMITS_H
Daniel Berlin committed
26
#include <limits.h>
27 28
#endif
#ifdef HAVE_STDLIB_H
Daniel Berlin committed
29
#include <stdlib.h>
30 31 32 33
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
Daniel Berlin committed
34 35 36 37
#include "libiberty.h"
#include "fibheap.h"


38 39
#define FIBHEAPKEY_MIN	LONG_MIN

40 41 42 43 44 45 46 47 48 49 50
static void fibheap_ins_root (fibheap_t, fibnode_t);
static void fibheap_rem_root (fibheap_t, fibnode_t);
static void fibheap_consolidate (fibheap_t);
static void fibheap_link (fibheap_t, fibnode_t, fibnode_t);
static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t);
static void fibheap_cascading_cut (fibheap_t, fibnode_t);
static fibnode_t fibheap_extr_min_node (fibheap_t);
static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t);
static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t);
static fibnode_t fibnode_new (void);
static void fibnode_insert_after (fibnode_t, fibnode_t);
Daniel Berlin committed
51
#define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b)
52
static fibnode_t fibnode_remove (fibnode_t);
Daniel Berlin committed
53

54

Daniel Berlin committed
55 56
/* Create a new fibonacci heap.  */
fibheap_t
57
fibheap_new (void)
Daniel Berlin committed
58
{
59
  return (fibheap_t) xcalloc (1, sizeof (struct fibheap));
60 61 62
}

/* Create a new fibonacci heap node.  */
63
static fibnode_t
64
fibnode_new (void)
65
{
66
  fibnode_t node;
67

68
  node = (fibnode_t) xcalloc (1, sizeof *node);
69 70
  node->left = node;
  node->right = node;
71

72
  return node;
73 74 75
}

static inline int
76
fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b)
77 78 79 80 81 82 83 84 85
{
  if (a->key < b->key)
    return -1;
  if (a->key > b->key)
    return 1;
  return 0;
}

static inline int
86
fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b)
Daniel Berlin committed
87
{
88 89 90 91 92 93
  struct fibnode a;

  a.key = key;
  a.data = data;

  return fibheap_compare (heap, &a, b);
Daniel Berlin committed
94 95 96 97
}

/* Insert DATA, with priority KEY, into HEAP.  */
fibnode_t
98
fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data)
Daniel Berlin committed
99 100
{
  fibnode_t node;
101

102 103
  /* Create the new node.  */
  node = fibnode_new ();
104

Daniel Berlin committed
105 106 107 108 109 110 111
  /* Set the node's data.  */
  node->data = data;
  node->key = key;

  /* Insert it into the root list.  */
  fibheap_ins_root (heap, node);

112 113
  /* If their was no minimum, or this key is less than the min,
     it's the new min.  */
Daniel Berlin committed
114 115 116 117 118 119 120 121 122 123
  if (heap->min == NULL || node->key < heap->min->key)
    heap->min = node;

  heap->nodes++;

  return node;
}

/* Return the data of the minimum node (if we know it).  */
void *
124
fibheap_min (fibheap_t heap)
Daniel Berlin committed
125 126 127 128 129 130 131 132 133
{
  /* If there is no min, we can't easily return it.  */
  if (heap->min == NULL)
    return NULL;
  return heap->min->data;
}

/* Return the key of the minimum node (if we know it).  */
fibheapkey_t
134
fibheap_min_key (fibheap_t heap)
Daniel Berlin committed
135 136 137 138 139 140 141 142 143
{
  /* If there is no min, we can't easily return it.  */
  if (heap->min == NULL)
    return 0;
  return heap->min->key;
}

/* Union HEAPA and HEAPB into a new heap.  */
fibheap_t
144
fibheap_union (fibheap_t heapa, fibheap_t heapb)
Daniel Berlin committed
145
{
146
  fibnode_t a_root, b_root, temp;
Daniel Berlin committed
147 148

  /* If one of the heaps is empty, the union is just the other heap.  */
149
  if ((a_root = heapa->root) == NULL)
Daniel Berlin committed
150
    {
151 152 153 154 155 156 157
      free (heapa);
      return heapb;
    }
  if ((b_root = heapb->root) == NULL)
    {
      free (heapb);
      return heapa;
Daniel Berlin committed
158
    }
159

Daniel Berlin committed
160
  /* Merge them to the next nodes on the opposite chain.  */
161 162 163 164 165
  a_root->left->right = b_root;
  b_root->left->right = a_root;
  temp = a_root->left;
  a_root->left = b_root->left;
  b_root->left = temp;
Daniel Berlin committed
166 167 168 169 170 171 172 173 174 175 176 177
  heapa->nodes += heapb->nodes;

  /* And set the new minimum, if it's changed.  */
  if (fibheap_compare (heapa, heapb->min, heapa->min) < 0)
    heapa->min = heapb->min;

  free (heapb);
  return heapa;
}

/* Extract the data of the minimum node from HEAP.  */
void *
178
fibheap_extract_min (fibheap_t heap)
Daniel Berlin committed
179 180
{
  fibnode_t z;
181
  void *ret = NULL;
Daniel Berlin committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

  /* If we don't have a min set, it means we have no nodes.  */
  if (heap->min != NULL)
    {
      /* Otherwise, extract the min node, free the node, and return the
         node's data.  */
      z = fibheap_extr_min_node (heap);
      ret = z->data;
      free (z);
    }

  return ret;
}

/* Replace both the KEY and the DATA associated with NODE.  */
void *
198 199
fibheap_replace_key_data (fibheap_t heap, fibnode_t node,
                          fibheapkey_t key, void *data)
Daniel Berlin committed
200 201
{
  void *odata;
202
  fibheapkey_t okey;
Daniel Berlin committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216
  fibnode_t y;

  /* If we wanted to, we could actually do a real increase by redeleting and
     inserting. However, this would require O (log n) time. So just bail out
     for now.  */
  if (fibheap_comp_data (heap, key, data, node) > 0)
    return NULL;

  odata = node->data;
  okey = node->key;
  node->data = data;
  node->key = key;
  y = node->parent;

217 218 219 220
  /* 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 != FIBHEAPKEY_MIN)
Daniel Berlin committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    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 && fibheap_compare (heap, node, y) <= 0)
    {
      fibheap_cut (heap, node, y);
      fibheap_cascading_cut (heap, y);
    }

  if (fibheap_compare (heap, node, heap->min) <= 0)
    heap->min = node;

  return odata;
}

238 239
/* Replace the DATA associated with NODE.  */
void *
240
fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data)
241 242 243 244 245 246
{
  return fibheap_replace_key_data (heap, node, node->key, data);
}

/* Replace the KEY associated with NODE.  */
fibheapkey_t
247
fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key)
248 249 250 251 252 253
{
  int okey = node->key;
  fibheap_replace_key_data (heap, node, key, node->data);
  return okey;
}

Daniel Berlin committed
254 255
/* Delete NODE from HEAP.  */
void *
256
fibheap_delete_node (fibheap_t heap, fibnode_t node)
Daniel Berlin committed
257
{
258 259
  void *ret = node->data;

Daniel Berlin committed
260
  /* To perform delete, we just make it the min key, and extract.  */
261
  fibheap_replace_key (heap, node, FIBHEAPKEY_MIN);
262 263 264 265 266
  if (node != heap->min)
    {
      fprintf (stderr, "Can't force minimum on fibheap.\n");
      abort ();
    }
Daniel Berlin committed
267 268
  fibheap_extract_min (heap);

269
  return ret;
Daniel Berlin committed
270 271 272 273
}

/* Delete HEAP.  */
void
274
fibheap_delete (fibheap_t heap)
Daniel Berlin committed
275 276 277 278 279 280 281 282 283
{
  while (heap->min != NULL)
    free (fibheap_extr_min_node (heap));

  free (heap);
}

/* Determine if HEAP is empty.  */
int
284
fibheap_empty (fibheap_t heap)
Daniel Berlin committed
285 286 287 288 289 290
{
  return heap->nodes == 0;
}

/* Extract the minimum node of the heap.  */
static fibnode_t
291
fibheap_extr_min_node (fibheap_t heap)
Daniel Berlin committed
292
{
293
  fibnode_t ret = heap->min;
Daniel Berlin committed
294 295 296 297
  fibnode_t 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.  */
298
  for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y)
Daniel Berlin committed
299 300 301 302 303 304 305
    {
      if (orig == NULL)
	orig = x;
      y = x->right;
      x->parent = NULL;
      fibheap_ins_root (heap, x);
    }
306

Daniel Berlin committed
307 308 309
  /* Remove the old root.  */
  fibheap_rem_root (heap, ret);
  heap->nodes--;
310

Daniel Berlin committed
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
  /* If we are left with no nodes, then the min is NULL.  */
  if (heap->nodes == 0)
    heap->min = NULL;
  else
    {
      /* Otherwise, consolidate to find new minimum, as well as do the reorg
         work that needs to be done.  */
      heap->min = ret->right;
      fibheap_consolidate (heap);
    }

  return ret;
}

/* Insert NODE into the root list of HEAP.  */
static void
327
fibheap_ins_root (fibheap_t heap, fibnode_t node)
Daniel Berlin committed
328 329 330 331 332 333 334 335 336 337
{
  /* If the heap is currently empty, the new node becomes the singleton
     circular root list.  */
  if (heap->root == NULL)
    {
      heap->root = node;
      node->left = node;
      node->right = node;
      return;
    }
338 339 340

  /* Otherwise, insert it in the circular root list between the root
     and it's right node.  */
Daniel Berlin committed
341 342 343 344 345
  fibnode_insert_after (heap->root, node);
}

/* Remove NODE from the rootlist of HEAP.  */
static void
346
fibheap_rem_root (fibheap_t heap, fibnode_t node)
Daniel Berlin committed
347 348 349 350 351 352 353 354 355
{
  if (node->left == node)
    heap->root = NULL;
  else
    heap->root = fibnode_remove (node);
}

/* Consolidate the heap.  */
static void
356
fibheap_consolidate (fibheap_t heap)
Daniel Berlin committed
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
{
  fibnode_t a[1 + 8 * sizeof (long)];
  fibnode_t w;
  fibnode_t y;
  fibnode_t x;
  int i;
  int d;
  int D;

  D = 1 + 8 * sizeof (long);

  memset (a, 0, sizeof (fibnode_t) * D);

  while ((w = heap->root) != NULL)
    {
      x = w;
      fibheap_rem_root (heap, w);
      d = x->degree;
      while (a[d] != NULL)
	{
	  y = a[d];
	  if (fibheap_compare (heap, x, y) > 0)
	    {
	      fibnode_t temp;
	      temp = x;
	      x = y;
	      y = temp;
	    }
	  fibheap_link (heap, y, x);
	  a[d] = NULL;
	  d++;
	}
      a[d] = x;
    }
  heap->min = NULL;
  for (i = 0; i < D; i++)
    if (a[i] != NULL)
      {
	fibheap_ins_root (heap, a[i]);
	if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0)
	  heap->min = a[i];
      }
}

/* Make NODE a child of PARENT.  */
static void
403 404
fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED,
              fibnode_t node, fibnode_t parent)
Daniel Berlin committed
405 406 407 408 409 410 411 412 413 414 415 416
{
  if (parent->child == NULL)
    parent->child = node;
  else
    fibnode_insert_before (parent->child, node);
  node->parent = parent;
  parent->degree++;
  node->mark = 0;
}

/* Remove NODE from PARENT's child list.  */
static void
417
fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent)
Daniel Berlin committed
418 419 420 421 422 423 424 425 426
{
  fibnode_remove (node);
  parent->degree--;
  fibheap_ins_root (heap, node);
  node->parent = NULL;
  node->mark = 0;
}

static void
427
fibheap_cascading_cut (fibheap_t heap, fibnode_t y)
Daniel Berlin committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
{
  fibnode_t z;

  while ((z = y->parent) != NULL)
    {
      if (y->mark == 0)
	{
	  y->mark = 1;
	  return;
	}
      else
	{
	  fibheap_cut (heap, y, z);
	  y = z;
	}
    }
}

static void
447
fibnode_insert_after (fibnode_t a, fibnode_t b)
Daniel Berlin committed
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
{
  if (a == a->right)
    {
      a->right = b;
      a->left = b;
      b->right = a;
      b->left = a;
    }
  else
    {
      b->right = a->right;
      a->right->left = b;
      a->right = b;
      b->left = a;
    }
}

static fibnode_t
466
fibnode_remove (fibnode_t node)
Daniel Berlin committed
467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
{
  fibnode_t ret;

  if (node == node->left)
    ret = NULL;
  else
    ret = node->left;

  if (node->parent != NULL && node->parent->child == node)
    node->parent->child = ret;

  node->right->left = node->left;
  node->left->right = node->right;

  node->parent = NULL;
  node->left = node;
  node->right = node;

  return ret;
}