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 }