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