heap_sort.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2017-2018.
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. //
  8. // See http://www.boost.org/libs/move for documentation.
  9. //
  10. //////////////////////////////////////////////////////////////////////////////
  11. //! \file
  12. #ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP
  13. #define BOOST_MOVE_DETAIL_HEAP_SORT_HPP
  14. #ifndef BOOST_CONFIG_HPP
  15. # include <boost/config.hpp>
  16. #endif
  17. #
  18. #if defined(BOOST_HAS_PRAGMA_ONCE)
  19. # pragma once
  20. #endif
  21. #include <boost/move/detail/config_begin.hpp>
  22. #include <boost/move/detail/workaround.hpp>
  23. #include <boost/move/detail/iterator_traits.hpp>
  24. #include <boost/move/algo/detail/is_sorted.hpp>
  25. #include <boost/move/utility_core.hpp>
  26. namespace boost { namespace movelib{
  27. template <class RandomAccessIterator, class Compare>
  28. class heap_sort_helper
  29. {
  30. typedef typename boost::movelib::iterator_traits<RandomAccessIterator>::size_type size_type;
  31. typedef typename boost::movelib::iterator_traits<RandomAccessIterator>::value_type value_type;
  32. static void adjust_heap(RandomAccessIterator first, size_type hole_index, size_type const len, value_type &value, Compare comp)
  33. {
  34. size_type const top_index = hole_index;
  35. size_type second_child = 2 * (hole_index + 1);
  36. while (second_child < len) {
  37. if (comp(*(first + second_child), *(first + (second_child - 1))))
  38. second_child--;
  39. *(first + hole_index) = boost::move(*(first + second_child));
  40. hole_index = second_child;
  41. second_child = 2 * (second_child + 1);
  42. }
  43. if (second_child == len) {
  44. *(first + hole_index) = boost::move(*(first + (second_child - 1)));
  45. hole_index = second_child - 1;
  46. }
  47. { //push_heap-like ending
  48. size_type parent = (hole_index - 1) / 2;
  49. while (hole_index > top_index && comp(*(first + parent), value)) {
  50. *(first + hole_index) = boost::move(*(first + parent));
  51. hole_index = parent;
  52. parent = (hole_index - 1) / 2;
  53. }
  54. *(first + hole_index) = boost::move(value);
  55. }
  56. }
  57. static void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  58. {
  59. size_type const len = size_type(last - first);
  60. if (len > 1) {
  61. size_type parent = len/2u - 1u;
  62. do {
  63. value_type v(boost::move(*(first + parent)));
  64. adjust_heap(first, parent, len, v, comp);
  65. }while (parent--);
  66. }
  67. }
  68. static void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  69. {
  70. size_type len = size_type(last - first);
  71. while (len > 1) {
  72. //move biggest to the safe zone
  73. --last;
  74. value_type v(boost::move(*last));
  75. *last = boost::move(*first);
  76. adjust_heap(first, size_type(0), --len, v, comp);
  77. }
  78. }
  79. public:
  80. static void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  81. {
  82. make_heap(first, last, comp);
  83. sort_heap(first, last, comp);
  84. BOOST_ASSERT(boost::movelib::is_sorted(first, last, comp));
  85. }
  86. };
  87. template <class RandomAccessIterator, class Compare>
  88. BOOST_MOVE_FORCEINLINE void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  89. {
  90. heap_sort_helper<RandomAccessIterator, Compare>::sort(first, last, comp);
  91. }
  92. }} //namespace boost { namespace movelib{
  93. #include <boost/move/detail/config_end.hpp>
  94. #endif //#ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP