繁体   English   中英

stable_partition并获取O(nlogn)交换

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM