获取向量<float>中 k 个最大值的 indize 的有效方法
Efficient way to get the indizes of the k highest values in vector<float>
从vector<float>
创建std::map<int, float>
,以便映射包含来自向量的 k 个最大值,键与向量中值的索引有关。
一种幼稚的方法是遍历向量(O(n)),提取和擦除(O(n))最高元素k次(O(k)),导致O(k*n^2)的复杂性,我猜这是次优的。
更好的是只复制(O(n))并删除最小的,直到大小为k。这将导致 O(n^2)。仍然是多项式...
有什么想法吗?
以下应该可以完成这项工作:
#include <cstdint>
#include <algorithm>
#include <iostream>
#include <map>
#include <tuple>
#include <vector>
// Compare: greater T2 first.
struct greater_by_second
{
template <typename T1, typename T2>
bool operator () (const std::pair<T1, T2>& lhs, const std::pair<T1, T2>& rhs)
{
return std::tie(lhs.second, lhs.first) > std::tie(rhs.second, rhs.first);
}
};
std::map<std::size_t, float> get_index_pairs(const std::vector<float>& v, int k)
{
std::vector<std::pair<std::size_t, float>> indexed_floats;
indexed_floats.reserve(v.size());
for (std::size_t i = 0, size = v.size(); i != size; ++i) {
indexed_floats.emplace_back(i, v[i]);
}
std::nth_element(indexed_floats.begin(),
indexed_floats.begin() + k,
indexed_floats.end(), greater_by_second());
return std::map<std::size_t, float>(indexed_floats.begin(), indexed_floats.begin() + k);
}
让我们测试一下:
int main(int argc, char *argv[])
{
const std::vector<float> fs {45.67f, 12.34f, 67.8f, 4.2f, 123.4f};
for (const auto& elem : get_index_pairs(fs, 2)) {
std::cout << elem.first << " " << elem.second << std::endl;
}
return 0;
}
输出:
2 67.8
4 123.4
您可以保留到目前为止 k 最大值的列表,并针对向量中的每个值更新它,这会将您降低到 O(n*log k)(假设每次更新最大值列表的日志 k)或者,对于朴素列表,O(kn)。
你可能会更接近O(n),但假设k可能很小,可能不值得付出努力。
您的最优解将具有 O(n+k*log(k)) 的复杂度,因为对 k 个元素进行排序可以简化为此复杂度,并且您必须至少查看每个元素一次。
我想到了两种可能的解决方案:
-
遍历向量,同时将所有元素添加到有界(大小 k)优先级队列/堆中,同时保留它们的索引。
-
创建包含原始索引的向量副本,即
std::vector<std::pair<float, std::size_t>>
并使用std::nth_element
使用仅比较第一个元素的比较器将 k 个最大值移动到前面。然后将这些元素插入到目标地图中。具有讽刺意味的是,最后一步在整体复杂性中增加了k*log(k),而nth_element是线性的(但会排列你的索引)。
也许我不明白,但如果增量方法不是一种选择,为什么不使用std::sort
std::partial_sort
?
这应该是一个 o(n log k),并且由于 k 很可能很小,这实际上是一个 o(n)。
编辑:感谢迈克·西摩的更新。编辑(之二):
这个想法是使用中间向量进行排序,然后将其放入地图中。试图减少计算顺序只适用于大量数据,所以我想复制时间(以 o(n) 为单位)可能会在背景噪音中丢失。
编辑(之二):
这实际上是所选答案的作用,没有:)的理论解释。
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 使用指针从C++中的数组中获取最大值
- 如何将这个C++哈希表转换为动态扩展和收缩,而不是使用硬设置的最大值
- 如何创建一个函数来计算并返回平均值、最大值和最小值
- 在二维数组中查找最小值和最大值?
- 整数溢出,最大值为 pow(10,19)
- 以C++递归方式查找向量中的最大值
- C++ - 如何在结构向量中找到结构体一个成员的最大值?
- 查找数组中第一个最小值和最后一个最大值元素之间的算术平均值
- C++ 函数,用于查找传入的 N 个数字的平均值、总和、最小值和最大值
- 我的 If Else 语句无法在向量 (C++) 中提供最大值
- 如何使用可变参数模板类使用模板元编程获得最大值
- C++不同的最小最大值实现
- Vec3b:r/g/b 颜色的最大值为 254,而不是 255
- CUDA - 将 float3 数组的 (x,y,z) 分量的最小值/最大值分开?
- 是否可以将无符号 int 的最大值转换为 int 并将结果转换为 -1?
- 查找包含 N 个元素的数组的最小值和最大值
- 井字游戏具有奇怪行为的最小最大值算法(C++)
- 错误C++在Visual Studio 2019中使用numeric_limits的长双精度最小值/最大值
- 获取向量<float>中 k 个最大值的 indize 的有效方法