从向量中提取最小值、最大值和中值的最有效方法是啥
Posted
技术标签:
【中文标题】从向量中提取最小值、最大值和中值的最有效方法是啥【英文标题】:What's the most efficient way to extract min, max & median from a vector从向量中提取最小值、最大值和中值的最有效方法是什么 【发布时间】:2019-10-20 16:31:25 【问题描述】:给定vector<T> vec...
,假设 T 是数字类型之一,提取其最小值、最大值和中值的最佳方法是什么?我知道std::nth_element
和std::minmax_element
,但如果一个接一个地调用它们,它们似乎会做多余的工作。
到目前为止,我想出的最好的想法是一次接一次地调用 std::nth_element 3 次。但这仍然需要 3N 比较,对吧?有没有办法重用之前迭代中完成的部分排序?
【问题讨论】:
最有效的方法是手动循环并同时计算。 @freakish 如何通过迭代元素获得中位数?std::partial_sort()
?
std::nth_element
,然后是左半边的 std::min_element
和右半边的 std::max_element
。
@DanielLangr, en.wikipedia.org/wiki/Quickselect
【参考方案1】:
使用std::nth_element
划分产生中位数,然后在左半部分使用std::min_element
,在右半部分使用std::max_element
。
如果您需要它比这更快,请根据 std::nth_element
推出您自己的版本。
【讨论】:
【参考方案2】:另一个选项是为std::nth_element
指定一个自定义比较,它捕获最小值和最大值。它可能最终会进行更多的比较和分支,因此在某些特定硬件上这可能会更慢,可能取决于缓存了多少数据等,因此 - 一如既往 - 如果你有理由关心,则进行基准测试,但是对于非空的vector
a
,该技术看起来像这样:
int min = a[0], max = a[0];
std::nth_element(a.begin(), a.begin() + n, a.end(),
[&](int lhs, int rhs)
min = std::min(min, std::min(lhs, rhs));
max = std::max(max, std::max(lhs, rhs));
return lhs < rhs;
);
在我的 (~10yo i5-660) HTPC 上使用 GCC 7.4 和 100 万个随机 int
s 在 0 到 1000 之间,nth_element
的最小/最大比较比没有。
【讨论】:
您假设std::nth_element
将至少检查所有元素一次。这是合理的,但在技术上并不能保证。
@BiagioFesta:有趣的点;语言规范不保证,但我认为它在逻辑上不可能正常工作......?
当然,在理论计算机科学中有一些关于算法复杂性的证明。但是,C++ 标准甚至没有指定使用哪种算法来实现std::nth_element
。如果我必须编写生产代码,我会自己实现完整的算法。
@BiagioFesta:这段代码的正确性与其时间复杂度不同。我会说这是不言而喻的,nth_element
重新排列输入数据实际上是不可能的,因为它需要为每个元素调用提供的比较函子 至少 一次,但是你'正确的是,当它多次调用它时,它可能会对性能产生不利影响/无法预测实现不透明时的严重程度;但在最坏的情况下,它会使比较加倍,所以没有大的-O 变化。不过可以衡量,这会让您了解是否值得担心。
在计算 (lhs以上是关于从向量中提取最小值、最大值和中值的最有效方法是啥的主要内容,如果未能解决你的问题,请参考以下文章
从 ColumnDataSource 列中提取最大值和最小值