使用std :: partition对矢量进行分区

时间:2016-06-11 23:00:48

标签: c++ performance c++11 vector

我在数据分区上划分数组。我尝试了std :: partition函数:

partition(sequence.begin(), sequence.end(), [&](int value) { return value < pivot; });

但是我希望将枢轴包含在两个序列的中间。我怎么能这样做,本地使用std :: partition或其他方法?我在这里寻找性能,所以解决方案应该相对较快。

2 个答案:

答案 0 :(得分:3)

最简单的方法是将数据透视表作为序列的最后一个元素,使用除最后一个元素以外的所有元素调用std::partition(),如果中间点与分区结束swap()元素不同,则到位:

sequence.push_back(pivot);
auto mid = std::partition(sequence.begin(), sequence.end() - 1,
                          [&](int value){ return value < pivot; });
if (mid != sequence.end() - 1) {
    std::swap(*mid, sequence.end()[-1]);
}

首先添加元素然后添加std::partition()而不是在std::partition()之后添加它,以避免处理可能重新定位的序列。

如果pivot在序列中开始,只需先std::swap()到最后,然后std::partition(),然后std::swap()将其放入中间。如果您的目标是胖分区,即所有等于pivot的元素都在中间,则您需要std::partition()相应的后半部分。标准C ++库没有直接进行胖分区的算法。

答案 1 :(得分:0)

你可以第二次给剩下的元素打电话partition

auto point = partition(sequence.begin(), sequence.end(),
    [&](int value) { return value < pivot; });
partition(point, sequence.end(), [&](int value) { return value == pivot; });

我继续根据这里的算法实现了一个三向分区:https://en.m.wikipedia.org/wiki/Dutch_national_flag_problem

template<typename IteratorT, typename ValueT>
std::pair<IteratorT, IteratorT>
three_way_partition(IteratorT _first, IteratorT _last, ValueT const& value) {
    auto i = _first;
    auto j = _first;
    auto k = _last - 1;
    while (j <= k) {
        if (*j < value) {
            std::swap(*i, *j);
            ++i;
            ++j;
        } else if (*j > value) {
            std::swap(*j, *k);
            --k;
        } else {
            ++j;
        }
    }

    return {i, j};
}

我用两次调用分区的方法对它进行了测试,而且我怀疑,性能上的差异可以忽略不计,实际上,分区两次方法通常会更快一点。自己测试并看看。