fheap

Fibonacci heap implementation
git clone git://www.tkruger.se/fheap.git
Log | Files | Refs | README

fheap.c (5123B)


      1 #include "fheap.h"
      2 
      3 void fnode_init(fnode_t *node, const uint64_t value, void *data) {
      4   node->children = NULL;
      5   node->parent = NULL;
      6   node->left = node;
      7   node->right = node;
      8   node->nchildren = 0;
      9   node->marked = 0;
     10 
     11   node->value = value;
     12   node->data = data;
     13 }
     14 
     15 void fnode_clear(fnode_t *node) {
     16   // clear children recursively
     17   fnode_t *c, *d;
     18   size_t n = node->nchildren;
     19   c = node->children;
     20   size_t i;
     21   for (i = 0; i < n; i++) {
     22     d = c->right;
     23     fnode_clear(c);
     24     c = d;
     25   }
     26 
     27   free(node);
     28 }
     29 
     30 void fheap_init(fheap_t *heap) {
     31   heap->min = NULL;
     32   heap->head = NULL;
     33   heap->n = 0;
     34 }
     35 
     36 void fheap_clear(fheap_t *heap) {
     37   fnode_t *c = heap->head;
     38   fnode_t *d = c->right;
     39 
     40   while (d != c) {
     41     fnode_t *t = d->right;
     42     fnode_clear(d);
     43     d = t;
     44   }
     45   fnode_clear(c);
     46 
     47   heap->min = NULL;
     48   heap->head = NULL;
     49   heap->n = 0;
     50 }
     51 
     52 static inline void insert_leftof(fnode_t *x, fnode_t *y) {
     53   fnode_t *x_left = x->left;
     54   x->left = y;
     55   y->parent = x->parent;
     56   y->right = x;
     57   y->left = x_left;
     58   x_left->right = y;
     59 }
     60 
     61 fnode_t *fheap_insert(fheap_t *heap, const uint64_t value, void *data) {
     62   assert(value != UINT64_MAX || data != NULL);
     63 
     64   fnode_t *nnode = malloc(sizeof(*nnode));
     65 
     66   fnode_init(nnode, value, data);
     67 
     68   if (heap->min == NULL) {
     69     heap->head = nnode;
     70     heap->min = nnode;
     71   } else {
     72     insert_leftof(heap->head, nnode);
     73     if (nnode->value < (heap->min)->value) {
     74       heap->min = nnode;
     75     }
     76   }
     77 
     78   heap->n++;
     79 
     80   return nnode;
     81 }
     82 
     83 static inline void remove_node(fnode_t *x) {
     84   (x->left)->right = x->right;
     85   (x->right)->left = x->left;
     86 }
     87 
     88 static inline void fheap_link(fheap_t *heap, fnode_t *y, fnode_t *x) {
     89   remove_node(y);
     90   if (heap->head == y)
     91     heap->head = y->right;
     92   if (x->children != NULL) {
     93     insert_leftof(x->children, y);
     94   } else {
     95     x->children = y;
     96     y->parent = x;
     97     y->left = y;
     98     y->right = y;
     99     x->nchildren = 0;
    100   }
    101   x->nchildren++;
    102   y->marked = 0;
    103 }
    104 
    105 static inline void consolidate(fheap_t *heap) {
    106   size_t i, deg;
    107   fnode_t *a[heap->n];
    108 
    109   for (i = 0; i < heap->n; i++)
    110     a[i] = NULL;
    111 
    112   fnode_t *c = heap->head;
    113   fnode_t *head_list[heap->n];
    114   size_t nheads = 0;
    115   do {
    116     head_list[nheads] = c;
    117     nheads++;
    118     c = c->right;
    119   } while (c != heap->head);
    120 
    121   size_t max_deg = 0;
    122 
    123   fnode_t *x, *y;
    124   for (i = 0; i < nheads; i++) {
    125     c = head_list[i];
    126 
    127     deg = c->nchildren;
    128     x = c;
    129     while (a[deg] != NULL) {
    130       if (x->value > a[deg]->value) {
    131         y = x;
    132         x = a[deg];
    133       } else {
    134         y = a[deg];
    135       }
    136 
    137       fheap_link(heap, y, x);
    138 
    139       a[deg] = NULL;
    140       deg++;
    141     }
    142 
    143     a[deg] = x;
    144 
    145     if (deg > max_deg)
    146       max_deg = deg;
    147   }
    148 
    149   heap->head = NULL;
    150   heap->min = NULL;
    151   for (i = 0; i < max_deg + 1; i++) {
    152     if (a[i] != NULL) {
    153       if (heap->head == NULL) {
    154         heap->head = a[i];
    155         heap->min = a[i];
    156         a[i]->left = a[i];
    157         a[i]->right = a[i];
    158       } else {
    159         insert_leftof(heap->head, a[i]);
    160         if (a[i]->value < (heap->min)->value)
    161           heap->min = a[i];
    162       }
    163     }
    164   }
    165 }
    166 
    167 fnode_t *fheap_extract_min_node(fheap_t *heap) {
    168   fnode_t *z = heap->min;
    169   fnode_t *c, *d;
    170   if (z != NULL) {
    171     if (z->nchildren > 0) {
    172       c = z->children;
    173       do {
    174         d = c->right;
    175         c->parent = NULL;
    176         insert_leftof(heap->head, c);
    177         c = d;
    178       } while (c != z->children);
    179       z->children = NULL;
    180     }
    181 
    182     remove_node(z);
    183 
    184     if (z == z->right) {
    185       heap->min = NULL;
    186       heap->head = NULL;
    187     } else {
    188       heap->min = z->right;
    189       if (heap->head == z)
    190         heap->head = z->right;
    191       consolidate(heap);
    192     }
    193 
    194     heap->n--;
    195   }
    196 
    197   return z;
    198 }
    199 
    200 uint64_t fheap_extract_min(void **data, fheap_t *heap) {
    201   fnode_t *z = fheap_extract_min_node(heap);
    202 
    203   if (z == NULL) {
    204     *data = NULL;
    205     return UINT64_MAX;
    206   }
    207 
    208   uint64_t value = z->value;
    209   *data = z->data;
    210 
    211   z->nchildren = 0;
    212   z->children = NULL;
    213   fnode_clear(z);
    214 
    215   return value;
    216 }
    217 
    218 static inline void fheap_cut(fheap_t *heap, fnode_t *x, fnode_t *y) {
    219   remove_node(x);
    220   if (y->children == x) {
    221     if (x->right == x) {
    222       y->children = NULL;
    223     } else {
    224       y->children = x->right;
    225     }
    226   }
    227   y->nchildren--;
    228 
    229   insert_leftof(heap->head, x);
    230   x->parent = NULL;
    231   x->marked = 0;
    232 }
    233 
    234 static void fheap_cascading_cut(fheap_t *heap, fnode_t *y) {
    235   fnode_t *z = y->parent;
    236   if (z != NULL) {
    237     if (y->marked == 0) {
    238       y->marked = 1;
    239     } else {
    240       fheap_cut(heap, y, z);
    241       fheap_cascading_cut(heap, z);
    242     }
    243   }
    244 }
    245 
    246 void fheap_decrease_value(fheap_t *heap, fnode_t *node, const uint64_t value) {
    247   node->value = value;
    248   fnode_t *y = node->parent;
    249   if (y != NULL && node->value < y->value) {
    250     fheap_cut(heap, node, y);
    251     fheap_cascading_cut(heap, y);
    252   }
    253 
    254   if (node->value < (heap->min)->value)
    255     heap->min = node;
    256 }
    257 
    258 void fheap_delete(fheap_t *heap, fnode_t *node) {
    259   node->value = 0; // at least tied minimum
    260 
    261   fnode_t *y = node->parent;
    262   if (y != NULL) {
    263     fheap_cut(heap, node, y);
    264     fheap_cascading_cut(heap, y);
    265   }
    266 
    267   heap->min = node;
    268   void* _throwaway;
    269   fheap_extract_min(&_throwaway, heap);
    270 }