is_permutation.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*
  2. Copyright (c) Marshall Clow 2011-2012.
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. */
  6. /// \file is_permutation.hpp
  7. /// \brief Is a sequence a permutation of another sequence
  8. /// \author Marshall Clow
  9. #ifndef BOOST_ALGORITHM_IS_PERMUTATION11_HPP
  10. #define BOOST_ALGORITHM_IS_PERMUTATION11_HPP
  11. #include <algorithm> // for std::find_if, count_if, mismatch
  12. #include <utility> // for std::pair
  13. #include <functional> // for std::equal_to
  14. #include <iterator>
  15. #include <boost/range/begin.hpp>
  16. #include <boost/range/end.hpp>
  17. #include <boost/utility/enable_if.hpp>
  18. #include <boost/type_traits/is_same.hpp>
  19. namespace boost { namespace algorithm {
  20. /// \cond DOXYGEN_HIDE
  21. namespace detail {
  22. template <typename Predicate, typename Iterator>
  23. struct value_predicate {
  24. value_predicate ( Predicate p, Iterator it ) : p_ ( p ), it_ ( it ) {}
  25. template <typename T1>
  26. bool operator () ( const T1 &t1 ) const { return p_ ( *it_, t1 ); }
  27. private:
  28. Predicate p_;
  29. Iterator it_;
  30. };
  31. // Preconditions:
  32. // 1. The sequences are the same length
  33. // 2. Any common elements on the front have been removed (not necessary for correctness, just for performance)
  34. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate >
  35. bool is_permutation_inner ( ForwardIterator1 first1, ForwardIterator1 last1,
  36. ForwardIterator2 first2, ForwardIterator2 last2,
  37. BinaryPredicate p ) {
  38. // for each unique value in the sequence [first1,last1), count how many times
  39. // it occurs, and make sure it occurs the same number of times in [first2, last2)
  40. for ( ForwardIterator1 iter = first1; iter != last1; ++iter ) {
  41. value_predicate<BinaryPredicate, ForwardIterator1> pred ( p, iter );
  42. /* For each value we haven't seen yet... */
  43. if ( std::find_if ( first1, iter, pred ) == iter ) {
  44. std::size_t dest_count = std::count_if ( first2, last2, pred );
  45. if ( dest_count == 0 || dest_count != (std::size_t) std::count_if ( iter, last1, pred ))
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate>
  52. bool is_permutation_tag ( ForwardIterator1 first1, ForwardIterator1 last1,
  53. ForwardIterator2 first2, ForwardIterator2 last2,
  54. BinaryPredicate p,
  55. std::forward_iterator_tag, std::forward_iterator_tag ) {
  56. // Skip the common prefix (if any)
  57. while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) {
  58. ++first1;
  59. ++first2;
  60. }
  61. if ( first1 != last1 && first2 != last2 )
  62. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2,
  63. std::equal_to<typename std::iterator_traits<ForwardIterator1>::value_type> ());
  64. return first1 == last1 && first2 == last2;
  65. }
  66. template <class RandomAccessIterator1, class RandomAccessIterator2, class BinaryPredicate>
  67. bool is_permutation_tag ( RandomAccessIterator1 first1, RandomAccessIterator1 last1,
  68. RandomAccessIterator2 first2, RandomAccessIterator2 last2,
  69. BinaryPredicate p,
  70. std::random_access_iterator_tag, std::random_access_iterator_tag ) {
  71. // Cheap check
  72. if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 ))
  73. return false;
  74. // Skip the common prefix (if any)
  75. while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) {
  76. ++first1;
  77. ++first2;
  78. }
  79. if ( first1 != last1 && first2 != last2 )
  80. return is_permutation_inner (first1, last1, first2, last2, p);
  81. return first1 == last1 && first2 == last2;
  82. }
  83. }
  84. /// \endcond
  85. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2, BinaryPredicate p )
  86. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  87. ///
  88. /// \param first1 The start of the input sequence
  89. /// \param last1 One past the end of the input sequence
  90. /// \param first2 The start of the second sequence
  91. /// \param p The predicate to compare elements with
  92. ///
  93. /// \note This function is part of the C++2011 standard library.
  94. template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate >
  95. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1,
  96. ForwardIterator2 first2, BinaryPredicate p )
  97. {
  98. // Skip the common prefix (if any)
  99. std::pair<ForwardIterator1, ForwardIterator2> eq = std::mismatch (first1, last1, first2, p);
  100. first1 = eq.first;
  101. first2 = eq.second;
  102. if ( first1 != last1 ) {
  103. // Create last2
  104. ForwardIterator2 last2 = first2;
  105. std::advance ( last2, std::distance (first1, last1));
  106. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, p );
  107. }
  108. return true;
  109. }
  110. /// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2 )
  111. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  112. ///
  113. /// \param first1 The start of the input sequence
  114. /// \param last2 One past the end of the input sequence
  115. /// \param first2 The start of the second sequence
  116. /// \note This function is part of the C++2011 standard library.
  117. template< class ForwardIterator1, class ForwardIterator2 >
  118. bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2 )
  119. {
  120. // How should I deal with the idea that ForwardIterator1::value_type
  121. // and ForwardIterator2::value_type could be different? Define my own comparison predicate?
  122. // Skip the common prefix (if any)
  123. std::pair<ForwardIterator1, ForwardIterator2> eq = std::mismatch (first1, last1, first2 );
  124. first1 = eq.first;
  125. first2 = eq.second;
  126. if ( first1 != last1 ) {
  127. // Create last2
  128. ForwardIterator2 last2 = first2;
  129. std::advance ( last2, std::distance (first1, last1));
  130. return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2,
  131. std::equal_to<typename std::iterator_traits<ForwardIterator1>::value_type> ());
  132. }
  133. return true;
  134. }
  135. /// \fn is_permutation ( const Range &r, ForwardIterator first2 )
  136. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  137. ///
  138. /// \param r The input range
  139. /// \param first2 The start of the second sequence
  140. template <typename Range, typename ForwardIterator>
  141. bool is_permutation ( const Range &r, ForwardIterator first2 )
  142. {
  143. return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2 );
  144. }
  145. /// \fn is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred )
  146. /// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2
  147. ///
  148. /// \param r The input range
  149. /// \param first2 The start of the second sequence
  150. /// \param pred The predicate to compare elements with
  151. ///
  152. // Disable this template when the first two parameters are the same type
  153. // That way the non-range version will be chosen.
  154. template <typename Range, typename ForwardIterator, typename BinaryPredicate>
  155. typename boost::disable_if_c<boost::is_same<Range, ForwardIterator>::value, bool>::type
  156. is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred )
  157. {
  158. return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2, pred );
  159. }
  160. }}
  161. #endif // BOOST_ALGORITHM_IS_PERMUTATION11_HPP