Difference between revisions of "cpp/algorithm/partition"
m (Text replace - "{{concept" to "{{named req") |
(Added LWG issue #2150 DR (part 6/12), and uses {{mark constexpr since c++20}}.) |
||
(13 intermediate revisions by 7 users not shown) | |||
Line 2: | Line 2: | ||
{{cpp/algorithm/navbar}} | {{cpp/algorithm/navbar}} | ||
{{dcl begin}} | {{dcl begin}} | ||
− | {{dcl header | algorithm}} | + | {{dcl header|algorithm}} |
− | {{dcl | + | {{dcl|num=1|notes={{mark constexpr since c++20}}| |
− | {{ | + | template< class ForwardIt, class UnaryPred > |
− | template< class | + | ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPred p ); |
− | + | ||
}} | }} | ||
− | {{dcl| | + | {{dcl|num=2|since=c++17| |
− | + | template< class ExecutionPolicy, class ForwardIt, class UnaryPred > | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | template< class ExecutionPolicy, class ForwardIt, class | + | |
ForwardIt partition( ExecutionPolicy&& policy, | ForwardIt partition( ExecutionPolicy&& policy, | ||
− | ForwardIt first, ForwardIt last, | + | ForwardIt first, ForwardIt last, UnaryPred p ); |
+ | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | @1@ Reorders the elements in the range {{ | + | @1@ Reorders the elements in the range {{range|first|last}} in such a way that all elements for which the predicate {{c|p}} returns {{c|true}} precede all elements for which predicate {{c|p}} returns {{c|false}}. Relative order of the elements is not preserved. |
+ | |||
+ | @2@ Same as {{v|1}}, but executed according to {{c|policy}}. | ||
+ | @@ {{cpp/algorithm/parallel overload precondition}} | ||
− | + | If {{rev inl|until=c++11|the type of {{c|*first}} is not {{named req|Swappable}}}}{{rev inl|since=c++11|{{tt|ForwardIt}} is not {{named req|ValueSwappable}}}}, the behavior is undefined. | |
===Parameters=== | ===Parameters=== | ||
{{par begin}} | {{par begin}} | ||
− | {{par | first, last | the range of elements to reorder}} | + | {{par|first, last|the range of elements to reorder}} |
{{par exec pol}} | {{par exec pol}} | ||
− | {{par pred1 | p | if the element should be ordered before other elements | p1=ForwardIt}} | + | {{par pred1|p|if the element should be ordered before other elements|p1=ForwardIt}} |
{{par hreq}} | {{par hreq}} | ||
− | {{par req | + | {{par req named|ForwardIt|ForwardIterator}} |
− | + | {{par req named|UnaryPred|Predicate}} | |
− | {{par req | + | |
{{par end}} | {{par end}} | ||
Line 42: | Line 35: | ||
===Complexity=== | ===Complexity=== | ||
− | Given N | + | Given {{mathjax-or|\(\scriptsize N\)|N}} as {{c|std::distance(first, last)}}: |
− | @1@ Exactly N applications of | + | |
− | @2@ {{ | + | @1@ Exactly {{mathjax-or|\(\scriptsize N\)|N}} applications of {{c|p}}. |
+ | @@ At most {{mathjax-or|\(\scriptsize N/2\)|N/2}} swaps if {{tt|ForwardIt}} meets the requirements of {{named req|BidirectionalIterator}}, and at most {{mathjax-or|\(\scriptsize N\)|N}} swaps otherwise. | ||
+ | |||
+ | @2@ {{mathjax-or|\(\scriptsize O(N)\)|O(N)}} applications of {{c|p}}. | ||
+ | @@ {{mathjax-or|\(\scriptsize O(N \cdot log(N))\)|O(N·log(N))}} swaps. | ||
===Exceptions=== | ===Exceptions=== | ||
− | {{cpp/algorithm/ | + | {{cpp/algorithm/parallel exceptions reporting behavior|singular=yes}} |
===Possible implementation=== | ===Possible implementation=== | ||
− | {{eq fun | 1= | + | Implements overload {{v|1}} preserving C++11 compatibility. |
− | template<class ForwardIt, class | + | {{eq fun|1= |
− | ForwardIt partition(ForwardIt first, ForwardIt last, | + | template<class ForwardIt, class UnaryPred> |
+ | ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred p) | ||
{ | { | ||
first = std::find_if_not(first, last, p); | first = std::find_if_not(first, last, p); | ||
− | if (first == last) return first; | + | if (first == last) |
− | + | return first; | |
− | for ( | + | |
− | if (p(*i)) { | + | for (auto i = std::next(first); i != last; ++i) |
+ | if (p(*i)) | ||
+ | { | ||
std::iter_swap(i, first); | std::iter_swap(i, first); | ||
++first; | ++first; | ||
} | } | ||
− | + | ||
return first; | return first; | ||
} | } | ||
− | |||
}} | }} | ||
===Example=== | ===Example=== | ||
{{example | {{example | ||
− | + | | | |
− | + | |code= | |
#include <algorithm> | #include <algorithm> | ||
+ | #include <forward_list> | ||
#include <iostream> | #include <iostream> | ||
#include <iterator> | #include <iterator> | ||
#include <vector> | #include <vector> | ||
− | |||
− | template <class ForwardIt> | + | template<class ForwardIt> |
− | + | void quicksort(ForwardIt first, ForwardIt last) | |
− | + | { | |
− | if(first == last) return; | + | if (first == last) |
− | auto pivot = *std::next(first, std::distance(first,last)/2); | + | return; |
− | + | ||
− | + | auto pivot = *std::next(first, std::distance(first, last) / 2); | |
− | + | auto middle1 = std::partition(first, last, [pivot](const auto& em) | |
− | + | { | |
+ | return em < pivot; | ||
+ | }); | ||
+ | auto middle2 = std::partition(middle1, last, [pivot](const auto& em) | ||
+ | { | ||
+ | return !(pivot < em); | ||
+ | }); | ||
+ | |||
quicksort(first, middle1); | quicksort(first, middle1); | ||
quicksort(middle2, last); | quicksort(middle2, last); | ||
− | + | } | |
int main() | int main() | ||
{ | { | ||
− | std::vector<int> v | + | std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
− | std::cout << "Original vector: | + | std::cout << "Original vector: "; |
− | for(int elem : v) std::cout << elem << ' '; | + | for (int elem : v) |
+ | std::cout << elem << ' '; | ||
− | auto it = std::partition(v.begin(), v.end(), [](int i){return i % 2 == 0;}); | + | auto it = std::partition(v.begin(), v.end(), [](int i) {return i % 2 == 0;}); |
− | std::cout << "\nPartitioned vector: | + | std::cout << "\nPartitioned vector: "; |
std::copy(std::begin(v), it, std::ostream_iterator<int>(std::cout, " ")); | std::copy(std::begin(v), it, std::ostream_iterator<int>(std::cout, " ")); | ||
− | std::cout << " * "; | + | std::cout << "* "; |
std::copy(it, std::end(v), std::ostream_iterator<int>(std::cout, " ")); | std::copy(it, std::end(v), std::ostream_iterator<int>(std::cout, " ")); | ||
− | + | ||
− | std::forward_list<int> fl | + | std::forward_list<int> fl {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92}; |
− | std::cout << "\nUnsorted list: | + | std::cout << "\nUnsorted list: "; |
− | for(int n : fl) std::cout << n << ' '; | + | for (int n : fl) |
− | + | std::cout << n << ' '; | |
− | + | ||
quicksort(std::begin(fl), std::end(fl)); | quicksort(std::begin(fl), std::end(fl)); | ||
− | std::cout << " | + | std::cout << "\nSorted using quicksort: "; |
− | for(int fi : fl) std::cout << fi << ' '; | + | for (int fi : fl) |
+ | std::cout << fi << ' '; | ||
std::cout << '\n'; | std::cout << '\n'; | ||
} | } | ||
− | | output = | + | |p=true |
− | Original vector: | + | |output= |
− | + | Original vector: 0 1 2 3 4 5 6 7 8 9 | |
− | Partitioned vector: | + | Partitioned vector: 0 8 2 6 4 * 5 3 7 1 9 |
− | + | Unsorted list: 1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92 | |
− | Unsorted list: | + | Sorted using quicksort: -8 -5 -4 -4 1 1 1 2 3 5 6 30 64 92 |
− | + | ||
− | Sorted using quicksort: | + | |
− | + | ||
}} | }} | ||
+ | |||
+ | ===Defect reports=== | ||
+ | {{dr list begin}} | ||
+ | {{dr list item|wg=lwg|dr=498|std=C++98|before={{tt|std::partition}} required {{c|first}} and<br>{{c|last}} to be {{named req|BidirectionalIterator}}|after=only required to be<br>{{named req|ForwardIterator}}}} | ||
+ | {{dr list item|wg=lwg|dr=2150|std=C++98|before={{tt|std::partition}} was only required to place one element<br>satisfying {{c|p}} before one element not satisfying {{c|p}}|after=corrected the<br>requirement}} | ||
+ | {{dr list end}} | ||
===See also=== | ===See also=== | ||
{{dsc begin}} | {{dsc begin}} | ||
− | {{dsc inc | cpp/algorithm/dsc is_partitioned}} | + | {{dsc inc|cpp/algorithm/dsc is_partitioned}} |
− | {{dsc inc | cpp/algorithm/dsc stable_partition}} | + | {{dsc inc|cpp/algorithm/dsc stable_partition}} |
− | + | {{dsc inc|cpp/algorithm/ranges/dsc partition}} | |
{{dsc end}} | {{dsc end}} | ||
− | + | {{langlinks|de|es|fr|it|ja|pt|ru|zh}} | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + |
Latest revision as of 00:08, 29 March 2024
Defined in header <algorithm>
|
||
template< class ForwardIt, class UnaryPred > ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPred p ); |
(1) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred > ForwardIt partition( ExecutionPolicy&& policy, |
(2) | (since C++17) |
[
first,
last)
in such a way that all elements for which the predicate p returns true precede all elements for which predicate p returns false. Relative order of the elements is not preserved.
std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true. |
(until C++20) |
std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true. |
(since C++20) |
If the type of *first is not Swappable(until C++11)ForwardIt
is not ValueSwappable(since C++11), the behavior is undefined.
Contents |
[edit] Parameters
first, last | - | the range of elements to reorder |
policy | - | the execution policy to use. See execution policy for details. |
p | - | unary predicate which returns true if the element should be ordered before other elements. The expression p(v) must be convertible to bool for every argument |
Type requirements | ||
-ForwardIt must meet the requirements of LegacyForwardIterator.
| ||
-UnaryPred must meet the requirements of Predicate.
|
[edit] Return value
Iterator to the first element of the second group.
[edit] Complexity
Given N as std::distance(first, last):
ForwardIt
meets the requirements of LegacyBidirectionalIterator, and at most N swaps otherwise.[edit] Exceptions
The overload with a template parameter named ExecutionPolicy
reports errors as follows:
- If execution of a function invoked as part of the algorithm throws an exception and
ExecutionPolicy
is one of the standard policies, std::terminate is called. For any otherExecutionPolicy
, the behavior is implementation-defined. - If the algorithm fails to allocate memory, std::bad_alloc is thrown.
[edit] Possible implementation
Implements overload (1) preserving C++11 compatibility.
template<class ForwardIt, class UnaryPred> ForwardIt partition(ForwardIt first, ForwardIt last, UnaryPred p) { first = std::find_if_not(first, last, p); if (first == last) return first; for (auto i = std::next(first); i != last; ++i) if (p(*i)) { std::iter_swap(i, first); ++first; } return first; } |
[edit] Example
#include <algorithm> #include <forward_list> #include <iostream> #include <iterator> #include <vector> template<class ForwardIt> void quicksort(ForwardIt first, ForwardIt last) { if (first == last) return; auto pivot = *std::next(first, std::distance(first, last) / 2); auto middle1 = std::partition(first, last, [pivot](const auto& em) { return em < pivot; }); auto middle2 = std::partition(middle1, last, [pivot](const auto& em) { return !(pivot < em); }); quicksort(first, middle1); quicksort(middle2, last); } int main() { std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; std::cout << "Original vector: "; for (int elem : v) std::cout << elem << ' '; auto it = std::partition(v.begin(), v.end(), [](int i) {return i % 2 == 0;}); std::cout << "\nPartitioned vector: "; std::copy(std::begin(v), it, std::ostream_iterator<int>(std::cout, " ")); std::cout << "* "; std::copy(it, std::end(v), std::ostream_iterator<int>(std::cout, " ")); std::forward_list<int> fl {1, 30, -4, 3, 5, -4, 1, 6, -8, 2, -5, 64, 1, 92}; std::cout << "\nUnsorted list: "; for (int n : fl) std::cout << n << ' '; quicksort(std::begin(fl), std::end(fl)); std::cout << "\nSorted using quicksort: "; for (int fi : fl) std::cout << fi << ' '; std::cout << '\n'; }
Possible output:
Original vector: 0 1 2 3 4 5 6 7 8 9 Partitioned vector: 0 8 2 6 4 * 5 3 7 1 9 Unsorted list: 1 30 -4 3 5 -4 1 6 -8 2 -5 64 1 92 Sorted using quicksort: -8 -5 -4 -4 1 1 1 2 3 5 6 30 64 92
[edit] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 498 | C++98 | std::partition required first andlast to be LegacyBidirectionalIterator |
only required to be LegacyForwardIterator |
LWG 2150 | C++98 | std::partition was only required to place one elementsatisfying p before one element not satisfying p |
corrected the requirement |
[edit] See also
(C++11) |
determines if the range is partitioned by the given predicate (function template) |
divides elements into two groups while preserving their relative order (function template) | |
(C++20) |
divides a range of elements into two groups (niebloid) |