apply_permutation.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. Copyright (c) Alexander Zaitsev <zamazan4ik@gmail.com>, 2017
  3. Distributed under the Boost Software License, Version 1.0. (See
  4. accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt)
  6. See http://www.boost.org/ for latest version.
  7. Based on https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115
  8. */
  9. /// \file apply_permutation.hpp
  10. /// \brief Apply permutation to a sequence.
  11. /// \author Alexander Zaitsev
  12. #ifndef BOOST_ALGORITHM_APPLY_PERMUTATION_HPP
  13. #define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP
  14. #include <algorithm>
  15. #include <type_traits>
  16. #include <boost/range/begin.hpp>
  17. #include <boost/range/end.hpp>
  18. namespace boost { namespace algorithm
  19. {
  20. /// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
  21. /// \brief Reorder item sequence with index sequence order
  22. ///
  23. /// \param item_begin The start of the item sequence
  24. /// \param item_end One past the end of the item sequence
  25. /// \param ind_begin The start of the index sequence.
  26. ///
  27. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  28. /// Complexity: O(N).
  29. template<typename RandomAccessIterator1, typename RandomAccessIterator2>
  30. void
  31. apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
  32. RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end)
  33. {
  34. using Diff = typename std::iterator_traits<RandomAccessIterator1>::difference_type;
  35. using std::swap;
  36. Diff size = std::distance(item_begin, item_end);
  37. for (Diff i = 0; i < size; i++)
  38. {
  39. auto current = i;
  40. while (i != ind_begin[current])
  41. {
  42. auto next = ind_begin[current];
  43. swap(item_begin[current], item_begin[next]);
  44. ind_begin[current] = current;
  45. current = next;
  46. }
  47. ind_begin[current] = current;
  48. }
  49. }
  50. /// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
  51. /// \brief Reorder item sequence with index sequence order
  52. ///
  53. /// \param item_begin The start of the item sequence
  54. /// \param item_end One past the end of the item sequence
  55. /// \param ind_begin The start of the index sequence.
  56. ///
  57. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  58. /// Complexity: O(N).
  59. template<typename RandomAccessIterator1, typename RandomAccessIterator2>
  60. void
  61. apply_reverse_permutation(
  62. RandomAccessIterator1 item_begin,
  63. RandomAccessIterator1 item_end,
  64. RandomAccessIterator2 ind_begin,
  65. RandomAccessIterator2 ind_end)
  66. {
  67. using Diff = typename std::iterator_traits<RandomAccessIterator2>::difference_type;
  68. using std::swap;
  69. Diff length = std::distance(item_begin, item_end);
  70. for (Diff i = 0; i < length; i++)
  71. {
  72. while (i != ind_begin[i])
  73. {
  74. Diff next = ind_begin[i];
  75. swap(item_begin[i], item_begin[next]);
  76. swap(ind_begin[i], ind_begin[next]);
  77. }
  78. }
  79. }
  80. /// \fn apply_permutation ( Range1 item_range, Range2 ind_range )
  81. /// \brief Reorder item sequence with index sequence order
  82. ///
  83. /// \param item_range The item sequence
  84. /// \param ind_range The index sequence
  85. ///
  86. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  87. /// Complexity: O(N).
  88. template<typename Range1, typename Range2>
  89. void
  90. apply_permutation(Range1& item_range, Range2& ind_range)
  91. {
  92. apply_permutation(boost::begin(item_range), boost::end(item_range),
  93. boost::begin(ind_range), boost::end(ind_range));
  94. }
  95. /// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range )
  96. /// \brief Reorder item sequence with index sequence order
  97. ///
  98. /// \param item_range The item sequence
  99. /// \param ind_range The index sequence
  100. ///
  101. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  102. /// Complexity: O(N).
  103. template<typename Range1, typename Range2>
  104. void
  105. apply_reverse_permutation(Range1& item_range, Range2& ind_range)
  106. {
  107. apply_reverse_permutation(boost::begin(item_range), boost::end(item_range),
  108. boost::begin(ind_range), boost::end(ind_range));
  109. }
  110. }}
  111. #endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP