apply_permutation.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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/config.hpp>
  17. #include <boost/range/begin.hpp>
  18. #include <boost/range/end.hpp>
  19. namespace boost { namespace algorithm
  20. {
  21. /// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
  22. /// \brief Reorder item sequence with index sequence order
  23. ///
  24. /// \param item_begin The start of the item sequence
  25. /// \param item_end One past the end of the item sequence
  26. /// \param ind_begin The start of the index sequence.
  27. ///
  28. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  29. /// Complexity: O(N).
  30. template<typename RandomAccessIterator1, typename RandomAccessIterator2>
  31. void
  32. apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
  33. RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end)
  34. {
  35. typedef typename std::iterator_traits<RandomAccessIterator1>::difference_type Diff;
  36. typedef typename std::iterator_traits<RandomAccessIterator2>::difference_type Index;
  37. using std::swap;
  38. Diff size = std::distance(item_begin, item_end);
  39. for (Diff i = 0; i < size; i++)
  40. {
  41. Diff current = i;
  42. while (i != ind_begin[current])
  43. {
  44. Index next = ind_begin[current];
  45. swap(item_begin[current], item_begin[next]);
  46. ind_begin[current] = current;
  47. current = next;
  48. }
  49. ind_begin[current] = current;
  50. }
  51. }
  52. /// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
  53. /// \brief Reorder item sequence with index sequence order
  54. ///
  55. /// \param item_begin The start of the item sequence
  56. /// \param item_end One past the end of the item sequence
  57. /// \param ind_begin The start of the index sequence.
  58. ///
  59. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  60. /// Complexity: O(N).
  61. template<typename RandomAccessIterator1, typename RandomAccessIterator2>
  62. void
  63. apply_reverse_permutation(
  64. RandomAccessIterator1 item_begin,
  65. RandomAccessIterator1 item_end,
  66. RandomAccessIterator2 ind_begin,
  67. RandomAccessIterator2 ind_end)
  68. {
  69. typedef typename std::iterator_traits<RandomAccessIterator2>::difference_type Diff;
  70. using std::swap;
  71. Diff length = std::distance(item_begin, item_end);
  72. for (Diff i = 0; i < length; i++)
  73. {
  74. while (i != ind_begin[i])
  75. {
  76. Diff next = ind_begin[i];
  77. swap(item_begin[i], item_begin[next]);
  78. swap(ind_begin[i], ind_begin[next]);
  79. }
  80. }
  81. }
  82. /// \fn apply_permutation ( Range1 item_range, Range2 ind_range )
  83. /// \brief Reorder item sequence with index sequence order
  84. ///
  85. /// \param item_range The item sequence
  86. /// \param ind_range The index sequence
  87. ///
  88. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  89. /// Complexity: O(N).
  90. template<typename Range1, typename Range2>
  91. void
  92. apply_permutation(Range1& item_range, Range2& ind_range)
  93. {
  94. apply_permutation(boost::begin(item_range), boost::end(item_range),
  95. boost::begin(ind_range), boost::end(ind_range));
  96. }
  97. /// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range )
  98. /// \brief Reorder item sequence with index sequence order
  99. ///
  100. /// \param item_range The item sequence
  101. /// \param ind_range The index sequence
  102. ///
  103. /// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
  104. /// Complexity: O(N).
  105. template<typename Range1, typename Range2>
  106. void
  107. apply_reverse_permutation(Range1& item_range, Range2& ind_range)
  108. {
  109. apply_reverse_permutation(boost::begin(item_range), boost::end(item_range),
  110. boost::begin(ind_range), boost::end(ind_range));
  111. }
  112. }}
  113. #endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP