BinaryHeap.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2024 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #pragma once
  5. JPH_NAMESPACE_BEGIN
  6. /// Push a new element into a binary max-heap.
  7. /// [inBegin, inEnd - 1) must be a a valid heap. Element inEnd - 1 will be inserted into the heap. The heap will be [inBegin, inEnd) after this call.
  8. /// inPred is a function that returns true if the first element is less or equal than the second element.
  9. /// See: https://en.wikipedia.org/wiki/Binary_heap
  10. template <typename Iterator, typename Pred>
  11. void BinaryHeapPush(Iterator inBegin, Iterator inEnd, Pred inPred)
  12. {
  13. using diff_t = typename std::iterator_traits<Iterator>::difference_type;
  14. using elem_t = typename std::iterator_traits<Iterator>::value_type;
  15. // New heap size
  16. diff_t count = std::distance(inBegin, inEnd);
  17. // Start from the last element
  18. diff_t current = count - 1;
  19. while (current > 0)
  20. {
  21. // Get current element
  22. elem_t &current_elem = *(inBegin + current);
  23. // Get parent element
  24. diff_t parent = (current - 1) >> 1;
  25. elem_t &parent_elem = *(inBegin + parent);
  26. // Sort them so that the parent is larger than the child
  27. if (inPred(parent_elem, current_elem))
  28. {
  29. std::swap(parent_elem, current_elem);
  30. current = parent;
  31. }
  32. else
  33. {
  34. // When there's no change, we're done
  35. break;
  36. }
  37. }
  38. }
  39. /// Pop an element from a binary max-heap.
  40. /// [inBegin, inEnd) must be a valid heap. The largest element will be removed from the heap. The heap will be [inBegin, inEnd - 1) after this call.
  41. /// inPred is a function that returns true if the first element is less or equal than the second element.
  42. /// See: https://en.wikipedia.org/wiki/Binary_heap
  43. template <typename Iterator, typename Pred>
  44. void BinaryHeapPop(Iterator inBegin, Iterator inEnd, Pred inPred)
  45. {
  46. using diff_t = typename std::iterator_traits<Iterator>::difference_type;
  47. // Begin by moving the highest element to the end, this is the popped element
  48. std::swap(*(inEnd - 1), *inBegin);
  49. // New heap size
  50. diff_t count = std::distance(inBegin, inEnd) - 1;
  51. // Start from the root
  52. diff_t largest = 0;
  53. for (;;)
  54. {
  55. // Get first child
  56. diff_t child = (largest << 1) + 1;
  57. // Check if we're beyond the end of the heap, if so the 2nd child is also beyond the end
  58. if (child >= count)
  59. break;
  60. // Remember the largest element from the previous iteration
  61. diff_t prev_largest = largest;
  62. // Check if first child is bigger, if so select it
  63. if (inPred(*(inBegin + largest), *(inBegin + child)))
  64. largest = child;
  65. // Switch to the second child
  66. ++child;
  67. // Check if second child is bigger, if so select it
  68. if (child < count && inPred(*(inBegin + largest), *(inBegin + child)))
  69. largest = child;
  70. // If there was no change, we're done
  71. if (prev_largest == largest)
  72. break;
  73. // Swap element
  74. std::swap(*(inBegin + prev_largest), *(inBegin + largest));
  75. }
  76. }
  77. JPH_NAMESPACE_END