【问题标题】:Partitioning a vector using std::partition使用 std::partition 对向量进行分区
【发布时间】:2016-10-12 15:51:06
【问题描述】:

我正在跨轴对数组进行分区。我尝试了 std::partition 函数:

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

但是我希望在两个序列的中间包含枢轴。我该如何做到这一点,无论是原生地使用 std::partition 还是其他方法?我在这里寻找性能,因此解决方案应该相对较快。

【问题讨论】:

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


【解决方案1】:

最简单的方法是使枢轴成为序列的最后一个元素,调用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()ing,而不是在std::partition() 之后添加它,避免了处理可能被重定位的序列的需要。

如果pivot 按顺序开始,只需先将std::swap() 插入到末尾,然后再将std::partition() 插入,然后再将std::swap() 插入到中间。如果您的目标是胖分区,即所有等于pivot 的元素都应该在中间,那么您需要相应地std::partition() 下半部分。标准 C++ 库没有直接进行胖分区的算法。

【讨论】:

  • 我在系统的第 5 行收到参数类型不匹配。
  • @CrazyPython:我修复了代码。只是一个愚蠢的遗漏。
  • 我真的应该编译示例代码...(也修正了其他错字)
  • 对未来观众的注意:对我来说,我使用了swap(sequence[pivot_pos], sequence.back());,因为枢轴已经在数组中。
  • 请原谅这个可能真的很愚蠢的问题,但是我怎样才能找到分区后枢轴的索引?
【解决方案2】:

您可以对剩余的元素再次调用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};
}

我对调用分区两次的方法进行了测试,正如我所怀疑的那样,性能差异可以忽略不计,实际上,两次分区方法通常会快一点。自己测试一下看看。

【讨论】:

  • 然而这会使计算时间加倍。
  • @CrazyPython:你确定吗?给定一个在一步中进行三向分区的假设函数,无论如何比较都必须进行两项检查。并且放置逻辑会更复杂。您可以编写这样的函数并进行比较。我敢打赌,无论哪种方式,您都不会注意到优势。
猜你喜欢
  • 2020-07-14
  • 2011-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
相关资源
最近更新 更多