[英]stable_partition and getting O(nlogn) swaps
在en.cppreference.com中 ,如果允许使用额外的内存,我们将看到std::stable_partition
进行O(n)交换。 我可以看到这一点。 每当我们在谓词为false的范围内找到一个元素时,就会将其交换到另一个缓冲区中。 最后,我们可以将这个额外的缓冲区复制到成功部分的末尾。 [我还假设在这种情况下,只能使用Forward迭代器来实现stable_partition
]
我没有得到的是,链接说,如果不允许使用额外的内存,最多stable_partition
进行O(nlogn)交换。 这是我的尝试。
#include <utility>
namespace cho {
template <typename BidirIt, typename Pred>
BidirIt stable_partition(BidirIt begin, BidirIt end, Pred p) {
BidirIt next_p = begin;
for(BidirIt it = begin; it != end; ++it) {
if(it == begin && p(*it)) {
next_p++;
continue;
}
if(p(*it)) {
std::swap(*next_p++, *it);
// riplle back swapped element to keep stability
BidirIt cur = it;
do {
BidirIt prev = --cur; cur++;
std::swap(*cur--, *prev--);
} while(cur != next_p);
}
}
return next_p;
}
template <typename ForwardIt, typename Pred>
ForwardIt partition(ForwardIt begin, ForwardIt end, Pred p) {
ForwardIt next_p = begin;
for(ForwardIt it = begin; it != end; ++it) {
if(p(*it)) {
std::swap(*next_p++, *it);
}
}
return next_p;
}
}
在这种情况下,交换后我会回荡。 因此,如果两个连续的真实情况之间的距离为k
,我将执行k
交换。 我认为,对于我的算法,当范围被反向分区时,会发生最坏的情况。 如果有p
个谓词为false的项目和np
个谓词为true的项目,我将获得O((n-p)* p)交换。 我考虑了一下,但看不到如何得到最坏的情况O(nlogn)。
我检查了LLVM中的实现,但无法真正获得O(nlogn)交换的实现方式。
PS:我的实现可能是错误的。 我用几个输入测试了它,仅此而已。
递归思考。
如果左半部分和右半部分都进行了稳定分区,例如
0...01...10...01...1
b m e
剩下的唯一操作是旋转b, e
范围,使m
到达b
所在的位置。 这将需要O(n)
交换。 现在以递归的方式思考,稳定的分区将两半。 将有O(log n)
个递归级别,总计O(n log n)
交换。 大胆地
iter stable_partition(begin, end) {
if (end - begin < 2)
return;
iter mid = begin + (end - begin) / 2;
iter left_break = stable_partition(begin, mid);
iter right_break = stable_partition(mid, end);
return rotate(left_break, mid, right_break);
}
当然,您必须仔细考虑rotate
应该返回什么。
我不了解C ++,所以我无法为您编写它,但是如果您有一个稳定的排序实现可用,这似乎很简单。 嗯,由于您需要不使用任何额外的内存,因此该实现也需要就地排序。 只要有这样的排序实现,只需根据以下顺序关系对元素进行排序:
R(x, y) = 0 if p(x) == p(y)
R(x, y) = -1 if p(x) && !p(y)
R(x, y) = 1 if !p(x) && p(y)
出于兴趣,哪种分类算法适合于此? 事实证明,似乎没有太多人可以勾选所有框,请参见此处 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.