我有一个双打矢量。我想从最高到最低排序,并获得前K个元素的索引。 std :: sort只是就地排序,并没有返回我认为的索引。什么是获得最大元素的前K个指数的快速方法?
答案 0 :(得分:13)
你可以使用nth_element
STL算法 - 这会返回N个最大的元素(这是最快的方法,使用stl),然后对它们使用.sort,或者你可以使用partial_sort算法,如果您希望对前K个元素进行排序(:
使用.sort非常糟糕 - 你想要的目的是非常慢.. .sort是很好的STL算法,但是对整个容器进行排序,而不仅仅是前K个元素(; nth_element和partial_sort的存在并非偶然;)
答案 1 :(得分:2)
首先想到的是有点hackish,但你可以定义一个存储double和它的原始索引的结构,然后重载<运算符基于double进行排序:
struct s {
double d;
int index;
bool operator < (const struct &s) const {
return d < s.d;
}
};
然后你可以从结构中检索原始索引。
富勒示例:
vector<double> orig;
vector<s> v;
...
for (int i=0; i < orig.size(); ++i) {
s s_temp;
s_temp.d = orig[i];
s_temp.index = i;
v.push_back(s);
}
sort(v.begin(), v.end());
//now just retrieve v[i].index
这将使它们从最小到最大排序,但你可以重载&gt;而不是运算符,如果需要,然后传入更大的sort函数。
答案 2 :(得分:0)
不确定预先制作的算法,但请查看selection algorithms;如果你需要一组N个值的前K个元素,并且N远大于K,那么有更多有效的方法。
如果你可以创建一个索引类(比如@ user470379的答案 - 基本上是一个将指针/索引封装到只读的“真实”数据的类),那么使用最大大小为K的优先级队列,将每个未排序的元素添加到优先级队列,当队列达到大小K + 1时弹出最底部的元素。在N = 10 6 ,K = 100的情况下,这比完全排序更简单+有效地处理案例。
答案 3 :(得分:0)
bool isSmaller (std::pair<double, int> x, std::pair<double, int> y)
{
return x.first< y.first;
}
int main()
{
//...
//you have your vector<double> here, say name is d;
std::vector<std::pair<double, int> > newVec(d.size());
for(int i = 0; i < newVec.size(); ++i)
{
newVec[i].first = d[i];
newVec[i].second = i; //store the initial index
}
std::sort(newVec.begin(), newVec.end(), &isSmaller);
//now you can iterate through first k elements and the second components will be the initial indices
}
答案 4 :(得分:0)
使用multimap
vector
(值,索引)来处理重复项。使用反向迭代器以降序排列结果。
#include <multimap>
#include <vector>
using namespace std;
multimap<double, size_t> indices;
vector<double> values;
values.push_back(1.0);
values.push_back(2.0);
values.push_back(3.0);
values.push_back(4.0);
size_t i = 0;
for(vector<double>::const_iterator iter = values.begin();
iter != values.end(); ++iter, ++i)
{
indices.insert(make_pair<double,int>(*iter, i));
}
i = 0;
size_t limit = 2;
for (multimap<double, size_t>::const_reverse_iterator iter = indices.rbegin();
iter != indices.rend() && i < limit; ++iter, ++i)
{
cout << "Value " << iter->first << " index " << iter->second << endl;
}
输出
价值4指数3
价值3指数2
如果您只想在排序后使用vector
索引,请使用:
#include <algorithm>
#include <vector>
using namespace std;
vector<double> values;
values.push_back(1.0);
values.push_back(2.0);
values.push_back(3.0);
values.push_back(4.0);
sort(values.rbegin(), values.rend());
前K个条目的索引为0到K-1,并按降序显示。这使用反向迭代器与标准sort
结合使用(使用less<double>
在向前迭代时实现降序。等效:
sort(values.rbegin(), values.rend(), less<double>());
@Kiril建议的优秀nth_element
解决方案的示例代码(K = 125000,N = 500000)。我想尝试一下,所以在这里。
vector<double> values;
for (size_t i = 0; i < 500000; ++i)
{
values.push_back(rand());
}
nth_element(values.begin(), values.begin()+375000, values.end());
sort(values.begin()+375000, values.end());
vector<double> results(values.rbegin(), values.rbegin() + values.size() - 375000);
答案 5 :(得分:0)
所以你实际上需要一个将索引映射到相应双精度的结构。
您可以使用std::multimap
类来执行此映射。正如Jason所说,std::map
不允许重复密钥。
std::vector<double> v; // assume it is populated already
std::multimap<double, int> m;
for (int i = 0; i < v.size(); ++i)
m.insert(std::make_pair(v[i], i));
...
完成此操作后,您可以迭代前十个元素,因为map会保留元素键的排序。