我在数据分区上划分数组。我尝试了std :: partition函数:
partition(sequence.begin(), sequence.end(), [&](int value) { return value < pivot; });
但是我希望将枢轴包含在两个序列的中间。我怎么能这样做,本地使用std :: partition或其他方法?我在这里寻找性能,所以解决方案应该相对较快。
答案 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};
}
我用两次调用分区的方法对它进行了测试,而且我怀疑,性能上的差异可以忽略不计,实际上,分区两次方法通常会更快一点。自己测试并看看。