heap_sort.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. #include <cassert>
  27. #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
  28. #pragma GCC diagnostic push
  29. #pragma GCC diagnostic ignored "-Wsign-conversion"
  30. #endif
  31. namespace boost { namespace movelib{
  32. template <class RandomAccessIterator, class Compare>
  33. class heap_sort_helper
  34. {
  35. typedef typename boost::movelib::iter_size<RandomAccessIterator>::type size_type;
  36. typedef typename boost::movelib::iterator_traits<RandomAccessIterator>::value_type value_type;
  37. static void adjust_heap(RandomAccessIterator first, size_type hole_index, size_type const len, value_type &value, Compare comp)
  38. {
  39. size_type const top_index = hole_index;
  40. size_type second_child = size_type(2u*(hole_index + 1u));
  41. while (second_child < len) {
  42. if (comp(*(first + second_child), *(first + size_type(second_child - 1u))))
  43. second_child--;
  44. *(first + hole_index) = boost::move(*(first + second_child));
  45. hole_index = second_child;
  46. second_child = size_type(2u * (second_child + 1u));
  47. }
  48. if (second_child == len) {
  49. *(first + hole_index) = boost::move(*(first + size_type(second_child - 1u)));
  50. hole_index = size_type(second_child - 1);
  51. }
  52. { //push_heap-like ending
  53. size_type parent = size_type((hole_index - 1u) / 2u);
  54. while (hole_index > top_index && comp(*(first + parent), value)) {
  55. *(first + hole_index) = boost::move(*(first + parent));
  56. hole_index = parent;
  57. parent = size_type((hole_index - 1u) / 2u);
  58. }
  59. *(first + hole_index) = boost::move(value);
  60. }
  61. }
  62. static void make_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  63. {
  64. size_type const len = size_type(last - first);
  65. if (len > 1) {
  66. size_type parent = size_type(len/2u - 1u);
  67. do {
  68. value_type v(boost::move(*(first + parent)));
  69. adjust_heap(first, parent, len, v, comp);
  70. }while (parent--);
  71. }
  72. }
  73. static void sort_heap(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  74. {
  75. size_type len = size_type(last - first);
  76. while (len > 1) {
  77. //move biggest to the safe zone
  78. --last;
  79. value_type v(boost::move(*last));
  80. *last = boost::move(*first);
  81. adjust_heap(first, size_type(0), --len, v, comp);
  82. }
  83. }
  84. public:
  85. static void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  86. {
  87. make_heap(first, last, comp);
  88. sort_heap(first, last, comp);
  89. assert(boost::movelib::is_sorted(first, last, comp));
  90. }
  91. };
  92. template <class RandomAccessIterator, class Compare>
  93. inline void heap_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
  94. {
  95. heap_sort_helper<RandomAccessIterator, Compare>::sort(first, last, comp);
  96. }
  97. }} //namespace boost { namespace movelib{
  98. #if defined(BOOST_CLANG) || (defined(BOOST_GCC) && (BOOST_GCC >= 40600))
  99. #pragma GCC diagnostic pop
  100. #endif
  101. #include <boost/move/detail/config_end.hpp>
  102. #endif //#ifndef BOOST_MOVE_DETAIL_HEAP_SORT_HPP