erlang各种有用的函数包括一些有用nif封装,还有一些性能测试case。
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

148 righe
2.7 KiB

5 anni fa
  1. #include "priority_queue.h"
  2. #include "erl_nif.h"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. // Algorithm described at : http://robin-thomas.github.io/min-heap/
  6. #define left(x) 2 * x + 1
  7. #define right(x) 2 * x + 2
  8. #define parent(x) (x - 1) / 2
  9. #define less(a, b) less_(heap_[a], heap_[b])
  10. PriorityQueue::PriorityQueue(LessFun ls, UpdatePositionFun upd, DestroyElementFun dtor) :
  11. capacity_(0),
  12. length_(0),
  13. heap_(NULL),
  14. less_(ls),
  15. update_pos_fun_(upd),
  16. item_dtor_(dtor) { }
  17. PriorityQueue::~PriorityQueue()
  18. {
  19. if(heap_)
  20. {
  21. for(int i = 0; i < length_; i++)
  22. item_dtor_(heap_[i]);
  23. enif_free(heap_);
  24. }
  25. }
  26. bool PriorityQueue::insert(void* item)
  27. {
  28. int pos;
  29. if (length_ == capacity_)
  30. {
  31. int new_capacity = (length_+1) * 2;
  32. void** new_heap = reinterpret_cast<void**>(enif_alloc(sizeof(void*) * new_capacity));
  33. if (!new_heap)
  34. return false;
  35. memcpy(new_heap, heap_, sizeof(void*)*length_);
  36. enif_free(heap_);
  37. heap_ = new_heap;
  38. capacity_ = new_capacity;
  39. }
  40. pos = (length_)++;
  41. set(pos, item);
  42. bubble_down(pos);
  43. return true;
  44. }
  45. bool PriorityQueue::remove(void* item, int pos)
  46. {
  47. if (pos >= length_)
  48. return false;
  49. if(heap_[pos] != item)
  50. return false;
  51. return remove(pos) == item;
  52. }
  53. void* PriorityQueue::remove(int pos)
  54. {
  55. if (pos >= length_)
  56. return NULL;
  57. void* item = heap_[pos];
  58. length_--;
  59. int ls = less(pos, length_);
  60. set(pos, heap_[length_]);
  61. if(ls)
  62. bubble_up(pos);
  63. else
  64. bubble_down(pos);
  65. // todo: resize down the heap in case we have a lot of empty slots
  66. update_pos_fun_(item, -1);
  67. return item;
  68. }
  69. void* PriorityQueue::peek()
  70. {
  71. if(length_ == 0)
  72. return NULL;
  73. return heap_[0];
  74. }
  75. // private
  76. void PriorityQueue::set(int pos, void* item)
  77. {
  78. heap_[pos] = item;
  79. update_pos_fun_(item, pos);
  80. }
  81. void PriorityQueue::pos_swap(int pos1, int pos2)
  82. {
  83. void* tmp = heap_[pos1];
  84. set(pos1, heap_[pos2]);
  85. set(pos2, tmp);
  86. }
  87. void PriorityQueue::bubble_down(int pos)
  88. {
  89. while(true)
  90. {
  91. int parent = parent(pos);
  92. if (pos == 0 || less(parent, pos))
  93. return;
  94. pos_swap(pos, parent);
  95. pos = parent;
  96. }
  97. }
  98. void PriorityQueue::bubble_up(int pos)
  99. {
  100. while (true)
  101. {
  102. int left = left(pos);
  103. int right = right(pos);
  104. int smallest = pos;
  105. if (left < length_ && less(left, smallest))
  106. smallest = left;
  107. if (right < length_ && less(right, smallest))
  108. smallest = right;
  109. if (smallest == pos)
  110. return;
  111. pos_swap(pos, smallest);
  112. pos = smallest;
  113. }
  114. }