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