stable_partition并获取O(nlogn)交换

时间:2018-09-16 15:34:17

标签: c++ algorithm stl

en.cppreference.com中,如果允许我们使用额外的内存,我们将看到std::stable_partition执行O(n)交换。我可以看到这一点。每当我们在谓词为false的范围内找到一个元素时,就会将其交换到另一个缓冲区中。最后,我们可以将这个额外的缓冲区复制到成功部分的末尾。 [我还假设在这种情况下,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的项目和n-p个谓词为true的项目,我将获得O((n-p)* p)交换。我考虑了一下,但看不到如何得到最坏的情况O(nlogn)。

我检查了LLVM中的实现,但无法真正了解如何实现O(nlogn)交换。

PS:我的实现可能是错误的。我用几个输入测试了它,仅此而已。

2 个答案:

答案 0 :(得分:3)

递归思考。

如果左半部分和右半部分都进行了稳定分区,如

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应该返回什么。

答案 1 :(得分:1)

我不了解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) 

出于兴趣,哪种排序算法适合于此?事实证明,似乎没有太多人可以勾选所有方框,请参见here