Difference between revisions of "cpp/algorithm/partition"
m (Text replace - "{{example cpp" to "{{example") |
(Added LWG issue #2150 DR (part 6/12), and uses {{mark constexpr since c++20}}.) |
||
(47 intermediate revisions by 21 users not shown) | |||
Line 1: | Line 1: | ||
{{cpp/title|partition}} | {{cpp/title|partition}} | ||
− | {{cpp/algorithm/ | + | {{cpp/algorithm/navbar}} |
− | {{ | + | {{dcl begin}} |
− | {{ | + | {{dcl header|algorithm}} |
− | {{ | + | {{dcl|num=1|notes={{mark constexpr since c++20}}| |
− | template< class | + | template< class ForwardIt, class UnaryPred > |
− | + | ForwardIt partition( ForwardIt first, ForwardIt last, UnaryPred p ); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
}} | }} | ||
− | {{ | + | {{dcl|num=2|since=c++17| |
+ | template< class ExecutionPolicy, class ForwardIt, class UnaryPred > | ||
+ | ForwardIt partition( ExecutionPolicy&& policy, | ||
+ | ForwardIt first, ForwardIt last, UnaryPred p ); | ||
+ | }} | ||
+ | {{dcl end}} | ||
+ | |||
+ | @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|first, last|the range of elements to reorder}} |
− | {{ | + | {{par exec pol}} |
− | {{ | + | {{par pred1|p|if the element should be ordered before other elements|p1=ForwardIt}} |
+ | {{par hreq}} | ||
+ | {{par req named|ForwardIt|ForwardIterator}} | ||
+ | {{par req named|UnaryPred|Predicate}} | ||
+ | {{par end}} | ||
===Return value=== | ===Return value=== | ||
− | + | Iterator to the first element of the second group. | |
− | Iterator to the first element of the second group | + | |
===Complexity=== | ===Complexity=== | ||
+ | Given {{mathjax-or|\(\scriptsize N\)|N}} as {{c|std::distance(first, last)}}: | ||
+ | |||
+ | @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=== | |
+ | {{cpp/algorithm/parallel exceptions reporting behavior|singular=yes}} | ||
===Possible implementation=== | ===Possible implementation=== | ||
− | {{eq fun | + | Implements overload {{v|1}} preserving C++11 compatibility. |
− | template<class | + | {{eq fun|1= |
− | + | 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; | ++first; | ||
} | } | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
return first; | return first; | ||
} | } | ||
− | |||
− | |||
}} | }} | ||
===Example=== | ===Example=== | ||
{{example | {{example | ||
− | + | | | |
− | + | |code= | |
#include <algorithm> | #include <algorithm> | ||
− | #include < | + | #include <forward_list> |
#include <iostream> | #include <iostream> | ||
#include <iterator> | #include <iterator> | ||
#include <vector> | #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() | int main() | ||
{ | { | ||
− | std::vector<int> v; | + | std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; |
− | for (int | + | std::cout << "Original vector: "; |
+ | for (int elem : v) | ||
+ | std::cout << elem << ' '; | ||
− | std:: | + | auto it = std::partition(v.begin(), v.end(), [](int i) {return i % 2 == 0;}); |
− | + | ||
− | + | std::cout << "\nPartitioned vector: "; | |
− | std:: | + | 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::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:: | + | std::cout << n << ' '; |
− | std::cout << "\ | + | |
− | + | quicksort(std::begin(fl), std::end(fl)); | |
+ | std::cout << "\nSorted using quicksort: "; | ||
+ | for (int fi : fl) | ||
+ | std::cout << fi << ' '; | ||
+ | std::cout << '\n'; | ||
} | } | ||
+ | |p=true | ||
+ | |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 | ||
}} | }} | ||
− | + | ===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=== |
− | | | + | {{dsc begin}} |
− | + | {{dsc inc|cpp/algorithm/dsc is_partitioned}} | |
− | + | {{dsc inc|cpp/algorithm/dsc stable_partition}} | |
− | + | {{dsc inc|cpp/algorithm/ranges/dsc partition}} | |
− | + | {{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) |