table of contents
        
      
      
    - Tumbleweed 2024.07.05-1.3
 - Leap-16.0
 
| std::ranges::stable_partition(3) | C++ Standard Libary | std::ranges::stable_partition(3) | 
NAME¶
std::ranges::stable_partition - std::ranges::stable_partition
Synopsis¶
 Defined in header <algorithm>
  
   Call signature
  
   template< std::bidirectional_iterator I, std::sentinel_for<I>
  
   S,
  
   class Proj = std::identity,
  
   std::indirect_unary_predicate<std::projected<I, (since C++20)
  
   Proj>> Pred > (1) (constexpr since
  
   requires std::permutable<I> C++26)
  
   ranges::subrange<I>
  
   stable_partition( I first, S last, Pred pred, Proj proj =
  
   {} );
  
   template< ranges::bidirectional_range R, class Proj =
  
   std::identity,
  
   std::indirect_unary_predicate< (since C++20)
  
   std::projected<ranges::iterator_t<R>, Proj>> Pred (2)
    (constexpr since
  
   > C++26)
  
   requires std::permutable<ranges::iterator_t<R>>
  
   ranges::borrowed_subrange_t<R>
  
   stable_partition( R&& r, Pred pred, Proj proj = {} );
  
   1) Reorders the elements in the range [first, last) in such a way that the
  
   projection proj of all elements for which the predicate pred returns true
    precede
  
   the projection proj of elements for which predicate pred returns false. The
  
   algorithms is stable, i.e. the relative order of elements is preserved.
  
   2) Same as (1), but uses r as the range, as if using ranges::begin(r)
    as first and
  
   ranges::end(r) as last.
  
   The function-like entities described on this page are niebloids, that is:
  
   * Explicit template argument lists cannot be specified when calling any of
    them.
  
   * None of them are visible to argument-dependent lookup.
  
   * When any of them are found by normal unqualified lookup as the name to the
    left
  
   of the function-call operator, argument-dependent lookup is inhibited.
  
   In practice, they may be implemented as function objects, or with special
    compiler
  
   extensions.
Parameters¶
 first, last - the range of elements to reorder
  
   r - the range of elements to reorder
  
   pred - predicate to apply to the projected elements
  
   proj - projection to apply to the elements
Return value¶
 1) An object equal to {pivot, last}, where pivot is an iterator
    to the first element
  
   of the second group.
  
   2) Same as (1) if r is an lvalue or of a borrowed_range type.
    Otherwise returns
  
   std::ranges::dangling.
Complexity¶
 Given N = ranges::distance(first, last), the complexity is at
    worst \(\scriptsize
  
   N\cdot\log{(N)}\)N·log(N) swaps, and only \(\scriptsize
    \mathcal{O}(N)\)𝓞(N) swaps
  
   in case an extra memory buffer is used. Exactly \(\scriptsize N\)N
    applications of
  
   the predicate pred and projection proj.
Notes¶
 This function attempts to allocate a temporary buffer. If the
    allocation fails, the
  
   less efficient algorithm is chosen.
  
   Feature-test macro Value Std Feature
  
   __cpp_lib_constexpr_algorithms 202306L constexpr stable sorting
Possible implementation¶
 This implementation does not use extra memory buffer and as such
    can be less
  
   efficient. See also the implementation in MSVC STL and libstdc++.
struct stable_partition_fn {
  
   template<std::bidirectional_iterator I, std::sentinel_for<I> S,
  
   class Proj = std::identity,
  
   std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
  
   requires std::permutable<I>
  
   constexpr ranges::subrange<I>
  
   operator()(I first, S last, Pred pred, Proj proj = {}) const
  
   {
  
   first = ranges::find_if_not(first, last, pred, proj);
  
   I mid = first;
  
   while (mid != last)
  
   {
  
   mid = ranges::find_if(mid, last, pred, proj);
  
   if (mid == last)
  
   break;
  
   I last2 = ranges::find_if_not(mid, last, pred, proj);
  
   ranges::rotate(first, mid, last2);
  
   first = ranges::next(first, ranges::distance(mid, last2));
  
   mid = last2;
  
   }
  
   return {std::move(first), std::move(mid)};
  
   }
  
   template<ranges::bidirectional_range R, class Proj = std::identity,
  
   std::indirect_unary_predicate<
  
   std::projected<ranges::iterator_t<R>, Proj>> Pred>
  
   requires std::permutable<ranges::iterator_t<R>>
  
   constexpr ranges::borrowed_subrange_t<R>
  
   operator()(R&& r, Pred pred, Proj proj = {}) const
  
   {
  
   return (*this)(ranges::begin(r), ranges::end(r), std::move(pred),
    std::move(proj));
  
   } };
inline constexpr stable_partition_fn stable_partition {};
Example¶
// Run this code
  
   #include <algorithm>
  
   #include <iostream>
  
   #include <iterator>
  
   #include <vector>
  
   namespace rng = std::ranges;
  
   template<std::permutable I, std::sentinel_for<I> S>
  
   constexpr void stable_sort(I first, S last)
  
   {
  
   if (first == last)
  
   return;
  
   auto pivot = *rng::next(first, rng::distance(first, last) / 2, last);
  
   auto left = [pivot](const auto& em) { return em < pivot; };
  
   auto tail1 = rng::stable_partition(first, last, left);
  
   auto right = [pivot](const auto& em) { return !(pivot < em); };
  
   auto tail2 = rng::stable_partition(tail1, right);
  
   stable_sort(first, tail1.begin());
  
   stable_sort(tail2.begin(), tail2.end());
  
   }
  
   void print(const auto rem, auto first, auto last, bool end = true)
  
   {
  
   std::cout << rem;
  
   for (; first != last; ++first)
  
   std::cout << *first << ' ';
  
   std::cout << (end ? "\n" : "");
  
   }
  
   int main()
  
   {
  
   const auto original = {9, 6, 5, 2, 3, 1, 7, 8};
  
   std::vector<int> vi {};
  
   auto even = [](int x) { return 0 == (x % 2); };
  
   print("Original vector:\t", original.begin(), original.end(),
    "\n");
  
   vi = original;
  
   const auto ret1 = rng::stable_partition(vi, even);
  
   print("Stable partitioned:\t", vi.begin(), ret1.begin(), 0);
  
   print("│ ", ret1.begin(), ret1.end());
  
   vi = original;
  
   const auto ret2 = rng::partition(vi, even);
  
   print("Partitioned:\t\t", vi.begin(), ret2.begin(), 0);
  
   print("│ ", ret2.begin(), ret2.end());
  
   vi = {16, 30, 44, 30, 15, 24, 10, 18, 12, 35};
  
   print("Unsorted vector: ", vi.begin(), vi.end());
  
   stable_sort(rng::begin(vi), rng::end(vi));
  
   print("Sorted vector: ", vi.begin(), vi.end());
  
   }
Possible output:¶
 Original vector: 9 6 5 2 3 1 7 8
  
   Stable partitioned: 6 2 8 │ 9 5 3 1 7
  
   Partitioned: 8 6 2 │ 5 3 1 7 9
  
   Unsorted vector: 16 30 44 30 15 24 10 18 12 35
  
   Sorted vector: 10 12 15 16 18 24 30 30 35 44
See also¶
 ranges::partition divides a range of elements into two groups
  
   (C++20) (niebloid)
  
   ranges::partition_copy copies a range dividing the elements into two groups
  
   (C++20) (niebloid)
  
   ranges::is_partitioned determines if the range is partitioned by the given
    predicate
  
   (C++20) (niebloid)
  
   divides elements into two groups while preserving their
  
   stable_partition relative order
  
   (function template)
| 2024.06.10 | http://cppreference.com |