heap.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include <string.h>
  2. #include "heap.h"
  3. static inline void swap_mem_(char* a, char* b, size_t elem_sz) {
  4. char* t = alloca(elem_sz);
  5. memcpy(t, a, elem_sz);
  6. memcpy(a, b, elem_sz);
  7. memcpy(b, t, elem_sz);
  8. }
  9. void heap_up_(heap_* h, size_t pi, size_t elem_sz);
  10. void heap_down_(heap_* h, size_t pi, size_t elem_sz);
  11. void heap_resize_(heap_* h, size_t new_size, size_t elem_sz) {
  12. if(!h->data) {
  13. h->data = malloc(elem_sz * 16);
  14. h->alloc = 16;
  15. }
  16. else {
  17. h->data = realloc(h->data, elem_sz * new_size);
  18. h->alloc = new_size;
  19. }
  20. }
  21. void heap_insert_(heap_* h, char* elem, size_t elem_sz) {
  22. if(h->len >= h->alloc) heap_resize_(h, h->alloc * 2, elem_sz);
  23. // insert the element at the end
  24. memcpy(h->data + (elem_sz * h->len), elem, elem_sz);
  25. h->len++;
  26. heap_up_(h, h->len-1, elem_sz);
  27. }
  28. int heap_peek_(heap_* h, char* out, size_t elem_sz) {
  29. if(h->len == 0) {
  30. return 1;
  31. }
  32. // copy the top element
  33. memcpy(out, h->data, elem_sz);
  34. return 0;
  35. }
  36. int heap_pop_(heap_* h, char* out, size_t elem_sz) {
  37. if(h->len == 0) {
  38. return 1;
  39. }
  40. // copy the top element
  41. memcpy(out, h->data, elem_sz);
  42. // swap
  43. swap_mem_(h->data + ((h->len-1) * elem_sz), h->data, elem_sz);
  44. h->len--;
  45. heap_down_(h, 0, elem_sz);
  46. return 0;
  47. }
  48. void heap_insert_pop_(heap_* h, char* in, char* out, size_t elem_sz) {
  49. // copy the top element out and the new element in
  50. if(h->len == 0) {
  51. memcpy(out, h->data, elem_sz);
  52. h->len++;
  53. }
  54. memcpy(h->data, in, elem_sz);
  55. heap_down_(h, 0, elem_sz);
  56. }
  57. void heap_delete_(heap_* h, char* elem, size_t elem_sz) {
  58. // find the item to be deleted
  59. ssize_t ind = heap_find_(h, elem, elem_sz);
  60. if(ind == -1) return;
  61. // swap with last item, then delete the new last item
  62. swap_mem_(h->data + (ind * elem_sz), h->data + ((h->len-1) * elem_sz), elem_sz);
  63. // rebalance heap with the new value in the deletion location
  64. heap_down_(h, ind, elem_sz);
  65. }
  66. void heap_free_(heap_* h) {
  67. if(h->data) free(h->data);
  68. h->data = NULL;
  69. h->len = 0;
  70. h->alloc = 0;
  71. }
  72. void heap_up_(heap_* h, size_t ci, size_t elem_sz) {
  73. while(ci != 0) {
  74. size_t pi = (ci - 1) / 2;
  75. int ret = h->cmp(h->data + (elem_sz * pi), h->data + (elem_sz * ci), h->user);
  76. if(ret > 0) break;
  77. swap_mem_(h->data + (elem_sz * pi), h->data + (elem_sz * ci), elem_sz);
  78. ci = pi;
  79. }
  80. }
  81. void heap_down_(heap_* h, size_t pi, size_t elem_sz) {
  82. size_t ai = (pi * 2) + 1;
  83. size_t bi = (pi * 2) + 2;
  84. size_t ci;
  85. int r;
  86. if(ai >= h->len) return;
  87. if(bi >= h->len) {
  88. ci = ai; // only one child
  89. }
  90. else {
  91. // find the smallest child
  92. r = h->cmp(h->data + (ai * elem_sz), h->data + (bi * elem_sz), h->user);
  93. ci = r > 0 ? ai : bi;
  94. }
  95. // printf("smaller: %d of %d and %d\n", *(int*)(h->data+ci*elem_sz),*(int*)(h->data+ai*elem_sz),*(int*)(h->data+bi*elem_sz));
  96. r = h->cmp(h->data + (ci * elem_sz), h->data + (pi * elem_sz), h->user);
  97. if(r > 0) {
  98. // printf(" -> %d < %d, swapping \n", *(int*)(h->data+ci*elem_sz),*(int*)(h->data+pi*elem_sz));
  99. swap_mem_(h->data + (ci * elem_sz), h->data + (pi * elem_sz), elem_sz);
  100. heap_down_(h, ci, elem_sz);
  101. return;
  102. }
  103. }
  104. ssize_t heap_find_(heap_* h, char* elem, size_t elem_sz) {
  105. int r;
  106. // TODO: replace with binary search, assuming it's actually faster
  107. for(size_t i = 0; i < h->len; i++) {
  108. if(0 == memcmp(h->data + i * elem_sz, elem, elem_sz)) return i;
  109. }
  110. return -1;
  111. }