diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-21 14:59:52 -0400 |
|---|---|---|
| committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-21 15:04:00 -0400 |
| commit | 5b73afc4eb1b0303cb92eb29a2ecc59c1db69537 (patch) | |
| tree | abf221060b4ddf8f4a8cf046a28966296d9a3b29 | |
| parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) | |
Binary heap implementation
Motivation: Linux's prio_heap.h is of fixed size. Litmus's binomial
heap may be overkill (and perhaps not general enough) for some applications.
Implemented in the style of linked lists.
| -rw-r--r-- | include/litmus/binheap.h | 543 |
1 files changed, 543 insertions, 0 deletions
diff --git a/include/litmus/binheap.h b/include/litmus/binheap.h new file mode 100644 index 000000000000..b8dd8e03da60 --- /dev/null +++ b/include/litmus/binheap.h | |||
| @@ -0,0 +1,543 @@ | |||
| 1 | #ifndef LITMUS_BINARY_HEAP_H | ||
| 2 | #define LITMUS_BINARY_HEAP_H | ||
| 3 | |||
| 4 | /** | ||
| 5 | * Simple binary heap with add, arbitrary delete, delete_root, and top | ||
| 6 | * operations. | ||
| 7 | * | ||
| 8 | * Style meant to conform with list.h. | ||
| 9 | * | ||
| 10 | * Motivation: Linux's prio_heap.h is of fixed size. Litmus's binomial | ||
| 11 | * heap may be overkill (and perhaps not general enough) for some applications. | ||
| 12 | * | ||
| 13 | * Note: In order to make node swaps fast, a node inserted with a data pointer | ||
| 14 | * may not always hold said data pointer. This is similar to the binomial heap | ||
| 15 | * implementation. This does make node deletion tricky since we have to | ||
| 16 | * (1) locate the node that holds the data pointer to delete, and (2) the | ||
| 17 | * node that was originally inserted with said data pointer. These have to be | ||
| 18 | * coalesced into a single node before removal (see usage of | ||
| 19 | * __binheap_safe_swap()). We have to track node references to accomplish this. | ||
| 20 | */ | ||
| 21 | |||
| 22 | struct binheap_node { | ||
| 23 | void *data; | ||
| 24 | struct binheap_node *parent; | ||
| 25 | struct binheap_node *left; | ||
| 26 | struct binheap_node *right; | ||
| 27 | |||
| 28 | /* pointer to binheap_node that holds *data for which this binheap_node | ||
| 29 | * was originally inserted. (*data "owns" this node) | ||
| 30 | */ | ||
| 31 | struct binheap_node *ref; | ||
| 32 | struct binheap_node **ref_ptr; | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Signature of compator function. Assumed 'less-than' (min-heap). | ||
| 37 | * Pass in 'greater-than' for max-heap. | ||
| 38 | * | ||
| 39 | * TODO: Consider macor-based implementation that allows comparator to be | ||
| 40 | * inlined (similar to Linux red/black tree) for greater efficiency. | ||
| 41 | */ | ||
| 42 | typedef int (*binheap_order_t)(struct binheap_node *a, | ||
| 43 | struct binheap_node *b); | ||
| 44 | |||
| 45 | |||
| 46 | struct binheap_handle { | ||
| 47 | struct binheap_node *root; | ||
| 48 | |||
| 49 | /* pointer to node to take next inserted child */ | ||
| 50 | struct binheap_node *next; | ||
| 51 | |||
| 52 | /* pointer to last node in complete binary tree */ | ||
| 53 | struct binheap_node *last; | ||
| 54 | |||
| 55 | /* comparator function pointer */ | ||
| 56 | binheap_order_t compare; | ||
| 57 | }; | ||
| 58 | |||
| 59 | |||
| 60 | /** | ||
| 61 | * binheap_entry - get the struct for this heap node. | ||
| 62 | * Only valid when called upon heap nodes other than the root handle. | ||
| 63 | * @ptr: the heap node. | ||
| 64 | * @type: the type of struct pointed to by binheap_node::data. | ||
| 65 | * @member: unused. | ||
| 66 | */ | ||
| 67 | #define binheap_entry(ptr, type, member) \ | ||
| 68 | ((type *)((ptr)->data)) | ||
| 69 | |||
| 70 | /** | ||
| 71 | * binheap_node_container - get the struct that contains this node. | ||
| 72 | * Only valid when called upon heap nodes other than the root handle. | ||
| 73 | * @ptr: the heap node. | ||
| 74 | * @type: the type of struct the node is embedded in. | ||
| 75 | * @member: the name of the binheap_struct within the (type) struct. | ||
| 76 | */ | ||
| 77 | #define binheap_node_container(ptr, type, member) \ | ||
| 78 | container_of((ptr), type, member) | ||
| 79 | |||
| 80 | /** | ||
| 81 | * binheap_top_entry - get the struct for the node at the top of the heap. | ||
| 82 | * Only valid when called upon the heap handle node. | ||
| 83 | * @ptr: the special heap-handle node. | ||
| 84 | * @type: the type of the struct the head is embedded in. | ||
| 85 | * @member: the name of the binheap_struct within the (type) struct. | ||
| 86 | */ | ||
| 87 | #define binheap_top_entry(ptr, type, member) \ | ||
| 88 | binheap_entry((ptr)->root, type, member) | ||
| 89 | |||
| 90 | /** | ||
| 91 | * binheap_delete_root - remove the root element from the heap. | ||
| 92 | * @handle: handle to the heap. | ||
| 93 | * @type: the type of the struct the head is embedded in. | ||
| 94 | * @member: the name of the binheap_struct within the (type) struct. | ||
| 95 | */ | ||
| 96 | #define binheap_delete_root(handle, type, member) \ | ||
| 97 | __binheap_delete_root((handle), &((type *)((handle)->root->data))->member) | ||
| 98 | |||
| 99 | /** | ||
| 100 | * binheap_delete - remove an arbitrary element from the heap. | ||
| 101 | * @to_delete: pointer to node to be removed. | ||
| 102 | * @handle: handle to the heap. | ||
| 103 | * @type: the type of the struct the head is embedded in. | ||
| 104 | * @member: the name of the binheap_struct within the (type) struct. | ||
| 105 | */ | ||
| 106 | #define binheap_delete(to_delete, handle, type, member) \ | ||
| 107 | __binheap_delete((to_delete), &((((type*)((to_delete)->data))->member)), (handle)) | ||
| 108 | |||
| 109 | /** | ||
| 110 | * binheap_add - insert an element to the heap | ||
| 111 | * new_node: node to add. | ||
| 112 | * @handle: handle to the heap. | ||
| 113 | * @type: the type of the struct the head is embedded in. | ||
| 114 | * @member: the name of the binheap_struct within the (type) struct. | ||
| 115 | */ | ||
| 116 | #define binheap_add(new_node, handle, type, member) \ | ||
| 117 | __binheap_add((new_node), (handle), container_of((new_node), type, member)) | ||
| 118 | |||
| 119 | |||
| 120 | #define BINHEAP_NODE_INIT() { NULL, NULL, NULL, NULL , NULL, NULL} | ||
| 121 | |||
| 122 | #define BINHEAP_NODE(name) \ | ||
| 123 | struct binheap_node name = BINHEAP_NODE_INIT() | ||
| 124 | |||
| 125 | |||
| 126 | static inline void INIT_BINHEAP_NODE(struct binheap_node *n) | ||
| 127 | { | ||
| 128 | n->data = NULL; | ||
| 129 | n->parent = NULL; | ||
| 130 | n->left = NULL; | ||
| 131 | n->right = NULL; | ||
| 132 | n->ref = NULL; | ||
| 133 | n->ref_ptr = NULL; | ||
| 134 | } | ||
| 135 | |||
| 136 | static inline void INIT_BINHEAP_HANDLE( | ||
| 137 | struct binheap_handle *handle, | ||
| 138 | binheap_order_t compare) | ||
| 139 | { | ||
| 140 | handle->root = NULL; | ||
| 141 | handle->next = NULL; | ||
| 142 | handle->last = NULL; | ||
| 143 | handle->compare = compare; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Returns true (1) if binheap is empty. */ | ||
| 147 | static inline int binheap_empty(struct binheap_handle *handle) | ||
| 148 | { | ||
| 149 | return(handle->root == NULL); | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | /* Update the node reference pointers. Same logic as Litmus binomial heap. */ | ||
| 154 | static inline void __update_ref(struct binheap_node *parent, | ||
| 155 | struct binheap_node *child) | ||
| 156 | { | ||
| 157 | *(parent->ref_ptr) = child; | ||
| 158 | *(child->ref_ptr) = parent; | ||
| 159 | |||
| 160 | swap(parent->ref_ptr, child->ref_ptr); | ||
| 161 | } | ||
| 162 | |||
| 163 | /* Swaps data between two nodes. */ | ||
| 164 | static inline void __binheap_swap(struct binheap_node *parent, | ||
| 165 | struct binheap_node *child) | ||
| 166 | { | ||
| 167 | swap(parent->data, child->data); | ||
| 168 | __update_ref(parent, child); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* Swaps memory and data between two nodes. Actual nodes swap instead of | ||
| 172 | * just data. Needed when we delete nodes from the heap. | ||
| 173 | */ | ||
| 174 | static inline void __binheap_swap_safe(struct binheap_handle *handle, | ||
| 175 | struct binheap_node *a, | ||
| 176 | struct binheap_node *b) | ||
| 177 | { | ||
| 178 | swap(a->data, b->data); | ||
| 179 | __update_ref(a, b); | ||
| 180 | |||
| 181 | if((a->parent != NULL) && (a->parent == b->parent)) { | ||
| 182 | /* special case: shared parent */ | ||
| 183 | swap(a->parent->left, a->parent->right); | ||
| 184 | } | ||
| 185 | else { | ||
| 186 | /* Update pointers to swap parents. */ | ||
| 187 | |||
| 188 | if(a->parent) { | ||
| 189 | if(a == a->parent->left) { | ||
| 190 | a->parent->left = b; | ||
| 191 | } | ||
| 192 | else { | ||
| 193 | a->parent->right = b; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | if(b->parent) { | ||
| 198 | if(b == b->parent->left) { | ||
| 199 | b->parent->left = a; | ||
| 200 | } | ||
| 201 | else { | ||
| 202 | b->parent->right = a; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | swap(a->parent, b->parent); | ||
| 207 | } | ||
| 208 | |||
| 209 | /* swap children */ | ||
| 210 | |||
| 211 | if(a->left) { | ||
| 212 | a->left->parent = b; | ||
| 213 | |||
| 214 | if(a->right) { | ||
| 215 | a->right->parent = b; | ||
| 216 | } | ||
| 217 | } | ||
| 218 | |||
| 219 | if(b->left) { | ||
| 220 | b->left->parent = a; | ||
| 221 | |||
| 222 | if(b->right) { | ||
| 223 | b->right->parent = a; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | swap(a->left, b->left); | ||
| 228 | swap(a->right, b->right); | ||
| 229 | |||
| 230 | |||
| 231 | /* update next/last/root pointers */ | ||
| 232 | |||
| 233 | if(a == handle->next) { | ||
| 234 | handle->next = b; | ||
| 235 | } | ||
| 236 | else if(b == handle->next) { | ||
| 237 | handle->next = a; | ||
| 238 | } | ||
| 239 | |||
| 240 | if(a == handle->last) { | ||
| 241 | handle->last = b; | ||
| 242 | } | ||
| 243 | else if(b == handle->last) { | ||
| 244 | handle->last = a; | ||
| 245 | } | ||
| 246 | |||
| 247 | if(a == handle->root) { | ||
| 248 | handle->root = b; | ||
| 249 | } | ||
| 250 | else if(b == handle->root) { | ||
| 251 | handle->root = a; | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | |||
| 256 | /** | ||
| 257 | * Update the pointer to the last node in the complete binary tree. | ||
| 258 | * Called internally after the root node has been deleted. | ||
| 259 | */ | ||
| 260 | static inline void __binheap_update_last(struct binheap_handle *handle) | ||
| 261 | { | ||
| 262 | struct binheap_node *temp = handle->last; | ||
| 263 | |||
| 264 | /* find a "bend" in the tree. */ | ||
| 265 | while(temp->parent && (temp == temp->parent->left)) { | ||
| 266 | temp = temp->parent; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* step over to sibling if we're not at root */ | ||
| 270 | if(temp->parent != NULL) { | ||
| 271 | temp = temp->parent->left; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* now travel right as far as possible. */ | ||
| 275 | while(temp->right != NULL) { | ||
| 276 | temp = temp->right; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* take one step to the left if we're not at the bottom-most level. */ | ||
| 280 | if(temp->left != NULL) { | ||
| 281 | temp = temp->left; | ||
| 282 | } | ||
| 283 | |||
| 284 | //BUG_ON(!(temp->left == NULL && temp->right == NULL)); | ||
| 285 | |||
| 286 | handle->last = temp; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * Update the pointer to the node that will take the next inserted node. | ||
| 291 | * Called internally after a node has been inserted. | ||
| 292 | */ | ||
| 293 | static inline void __binheap_update_next(struct binheap_handle *handle) | ||
| 294 | { | ||
| 295 | struct binheap_node *temp = handle->next; | ||
| 296 | |||
| 297 | /* find a "bend" in the tree. */ | ||
| 298 | while(temp->parent && (temp == temp->parent->right)) { | ||
| 299 | temp = temp->parent; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* step over to sibling if we're not at root */ | ||
| 303 | if(temp->parent != NULL) { | ||
| 304 | temp = temp->parent->right; | ||
| 305 | } | ||
| 306 | |||
| 307 | /* now travel left as far as possible. */ | ||
| 308 | while(temp->left != NULL) { | ||
| 309 | temp = temp->left; | ||
| 310 | } | ||
| 311 | |||
| 312 | handle->next = temp; | ||
| 313 | } | ||
| 314 | |||
| 315 | |||
| 316 | |||
| 317 | /* bubble node up towards root */ | ||
| 318 | static inline void __binheap_bubble_up( | ||
| 319 | struct binheap_handle *handle, | ||
| 320 | struct binheap_node *node) | ||
| 321 | { | ||
| 322 | /* Note: NULL data pointers are used internally for arbitrary delete */ | ||
| 323 | while((node->parent != NULL) && | ||
| 324 | ((node->data == NULL) /* let null data bubble to the top */ || | ||
| 325 | handle->compare(node, node->parent))) { | ||
| 326 | __binheap_swap(node->parent, node); | ||
| 327 | node = node->parent; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | |||
| 332 | /* bubble node down, swapping with min-child */ | ||
| 333 | static inline void __binheap_bubble_down(struct binheap_handle *handle) | ||
| 334 | { | ||
| 335 | struct binheap_node *node = handle->root; | ||
| 336 | |||
| 337 | while(node->left != NULL) { | ||
| 338 | if(node->right && handle->compare(node->right, node->left)) { | ||
| 339 | if(handle->compare(node->right, node)) { | ||
| 340 | __binheap_swap(node, node->right); | ||
| 341 | node = node->right; | ||
| 342 | } | ||
| 343 | else { | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | else { | ||
| 348 | if(handle->compare(node->left, node)) { | ||
| 349 | __binheap_swap(node, node->left); | ||
| 350 | node = node->left; | ||
| 351 | } | ||
| 352 | else { | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 359 | |||
| 360 | |||
| 361 | static inline void __binheap_add(struct binheap_node *new_node, | ||
| 362 | struct binheap_handle *handle, | ||
| 363 | void *data) | ||
| 364 | { | ||
| 365 | /* NULL data pointers are used internally */ | ||
| 366 | if(!data) { | ||
| 367 | WARN(); | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | |||
| 371 | new_node->data = data; | ||
| 372 | new_node->ref = new_node; | ||
| 373 | new_node->ref_ptr = &(new_node->ref); | ||
| 374 | |||
| 375 | if(!binheap_empty(handle)) { | ||
| 376 | /* insert left side first */ | ||
| 377 | if(handle->next->left == NULL) { | ||
| 378 | handle->next->left = new_node; | ||
| 379 | new_node->parent = handle->next; | ||
| 380 | new_node->left = NULL; | ||
| 381 | new_node->right = NULL; | ||
| 382 | |||
| 383 | handle->last = new_node; | ||
| 384 | |||
| 385 | __binheap_bubble_up(handle, new_node); | ||
| 386 | } | ||
| 387 | else { | ||
| 388 | /* left occupied. insert right. */ | ||
| 389 | handle->next->right = new_node; | ||
| 390 | new_node->parent = handle->next; | ||
| 391 | new_node->left = NULL; | ||
| 392 | new_node->right = NULL; | ||
| 393 | |||
| 394 | handle->last = new_node; | ||
| 395 | |||
| 396 | __binheap_update_next(handle); | ||
| 397 | __binheap_bubble_up(handle, new_node); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | else { | ||
| 401 | /* first node in heap */ | ||
| 402 | |||
| 403 | new_node->parent = NULL; | ||
| 404 | new_node->left = NULL; | ||
| 405 | new_node->right = NULL; | ||
| 406 | |||
| 407 | handle->root = new_node; | ||
| 408 | handle->next = new_node; | ||
| 409 | handle->last = new_node; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | |||
| 414 | |||
| 415 | /** | ||
| 416 | * Removes the root node from the heap. The node is removed after coalescing | ||
| 417 | * the binheap_node with its original data pointer at the root of the tree. | ||
| 418 | * | ||
| 419 | * The 'last' node in the tree is then swapped up to the root and bubbled | ||
| 420 | * down. | ||
| 421 | */ | ||
| 422 | static inline void __binheap_delete_root(struct binheap_handle *handle, | ||
| 423 | struct binheap_node *container) | ||
| 424 | { | ||
| 425 | struct binheap_node *root = handle->root; | ||
| 426 | |||
| 427 | if(root != container) { | ||
| 428 | /* coalesce */ | ||
| 429 | __binheap_swap_safe(handle, root, container); | ||
| 430 | root = container; | ||
| 431 | } | ||
| 432 | |||
| 433 | if(handle->last != root) { | ||
| 434 | /* swap 'last' node up to root and bubble it down. */ | ||
| 435 | |||
| 436 | struct binheap_node *to_move = handle->last; | ||
| 437 | |||
| 438 | if(to_move->parent != root) { | ||
| 439 | handle->next = to_move->parent; | ||
| 440 | |||
| 441 | if(handle->next->right == to_move) { | ||
| 442 | /* disconnect from parent */ | ||
| 443 | to_move->parent->right = NULL; | ||
| 444 | handle->last = handle->next->left; | ||
| 445 | } | ||
| 446 | else { | ||
| 447 | /* find new 'last' before we disconnect */ | ||
| 448 | __binheap_update_last(handle); | ||
| 449 | |||
| 450 | /* disconnect from parent */ | ||
| 451 | to_move->parent->left = NULL; | ||
| 452 | } | ||
| 453 | } | ||
| 454 | else { | ||
| 455 | /* 'last' is direct child of root */ | ||
| 456 | |||
| 457 | handle->next = to_move; | ||
| 458 | |||
| 459 | if(to_move == to_move->parent->right) { | ||
| 460 | to_move->parent->right = NULL; | ||
| 461 | handle->last = to_move->parent->left; | ||
| 462 | } | ||
| 463 | else { | ||
| 464 | to_move->parent->left = NULL; | ||
| 465 | handle->last = to_move; | ||
| 466 | } | ||
| 467 | } | ||
| 468 | to_move->parent = NULL; | ||
| 469 | |||
| 470 | /* reconnect as root. We can't just swap data ptrs since root node | ||
| 471 | * may be freed after this function returns. | ||
| 472 | */ | ||
| 473 | to_move->left = root->left; | ||
| 474 | to_move->right = root->right; | ||
| 475 | if(to_move->left != NULL) { | ||
| 476 | to_move->left->parent = to_move; | ||
| 477 | } | ||
| 478 | if(to_move->right != NULL) { | ||
| 479 | to_move->right->parent = to_move; | ||
| 480 | } | ||
| 481 | |||
| 482 | handle->root = to_move; | ||
| 483 | |||
| 484 | /* bubble down */ | ||
| 485 | __binheap_bubble_down(handle); | ||
| 486 | } | ||
| 487 | else { | ||
| 488 | /* removing last node in tree */ | ||
| 489 | handle->root = NULL; | ||
| 490 | handle->next = NULL; | ||
| 491 | handle->last = NULL; | ||
| 492 | } | ||
| 493 | } | ||
| 494 | |||
| 495 | |||
| 496 | /** | ||
| 497 | * Delete an arbitrary node. We first coalesce, then bubble | ||
| 498 | * node to delete up to the root, and then delete to root. | ||
| 499 | */ | ||
| 500 | static inline void __binheap_delete( | ||
| 501 | struct binheap_node *node_to_delete, | ||
| 502 | struct binheap_node *user_of_node, | ||
| 503 | struct binheap_handle *handle) | ||
| 504 | { | ||
| 505 | struct binheap_node *root, *target; | ||
| 506 | void *temp_data; | ||
| 507 | |||
| 508 | /* Position the node to delete at the root. */ | ||
| 509 | |||
| 510 | /* coalesce: swap nodes with user of the node to delete. */ | ||
| 511 | if(node_to_delete != user_of_node) { | ||
| 512 | /* we need to take container's memory/node out of the heap, | ||
| 513 | * so swap with the user of the node | ||
| 514 | */ | ||
| 515 | __binheap_swap_safe(handle, user_of_node, node_to_delete); | ||
| 516 | } | ||
| 517 | |||
| 518 | root = handle->root; | ||
| 519 | |||
| 520 | /* Move the _node_ to the root */ | ||
| 521 | if(root != node_to_delete) { | ||
| 522 | __binheap_swap_safe(handle, root, node_to_delete); | ||
| 523 | node_to_delete = root; | ||
| 524 | } | ||
| 525 | |||
| 526 | node_to_delete = handle->root; | ||
| 527 | target = node_to_delete->ref; | ||
| 528 | |||
| 529 | /* Bubble the data pointer back up to its node, which has already been | ||
| 530 | * positioned at the root. */ | ||
| 531 | |||
| 532 | /* temporarily set data to null to allow node to bubble up to the top. */ | ||
| 533 | temp_data = target->data; | ||
| 534 | target->data = NULL; | ||
| 535 | |||
| 536 | __binheap_bubble_up(handle, target); | ||
| 537 | __binheap_delete_root(handle, node_to_delete); | ||
| 538 | |||
| 539 | node_to_delete->data = temp_data; /* restore node data pointer */ | ||
| 540 | } | ||
| 541 | |||
| 542 | #endif | ||
| 543 | |||
