在related question中,我询问如何在c ++的对象向量中获取max元素的值,该对象是基于所述对象的某个字段。我扩展了算法以获得该max元素的索引,以便稍后我可以从对象的向量中弹出它。
这是我现在使用的代码,它运行正常:
vector<MyOwnClass> scoretracker // MyOwnClass has a ".score" field
// Some code filling scoretracker
auto max = std::max_element(scoretracker.begin(), scoretracker.end(),
[] (const MyOwnClass &a, const MyOwnClass &b )
{
return a.score < b.score; // I am not sure how this line works
});
int index = distance(scoretracker.begin(), max);
所以,我试图修改它以获得第二高(或第n个值)而不是最大值,但到目前为止我的尝试失败了。
这让我意识到我并不真正理解为什么“返回a.score&lt; b.score”会返回最高值。
通过查看max_element works的方式,我不确定它是否可以用来找到第二大。
哦,最后,我宁愿不从向量中弹出最高值,找到新的最大值(原始向量中的第二高值)并添加一些逻辑来恢复原始版本。好吧,如果我必须,我会这样做,但可能会有一些迭代器属性或其他我不知道的东西......
答案 0 :(得分:3)
如果您只需要一次索引(而不是所有值),您可以使用:
std::size_t get_index_of_nth_greatest(const std::vector<MyOwnClass>& v, std::size_t k)
{
std::vector<std::size_t> indexes(v.size());
std::iota(indexes.begin(), indexes.end(), 0);
std::nth_element(indexes.begin(), indexes.begin() + k, indexes.end(),
[&](int lhs, int rhs)
{
return v[lhs].score > v[rhs].score;
}
);
return indexes[k];
}
注意:由于来自莫斯科的 Vlad 指出,对于重复的输入,没有保证重复的顺序,因此您可能有不同的索引k
。
答案 1 :(得分:2)
试试这个:
auto max = std::sort(scoretracker.begin(), scoretracker.end(),
[] (const MyOwnClass &a, const MyOwnClass &b )
{
return a.score < b.score;
});
然后
scoretracker.back().score;
会给你最后一个元素
scoretracker.at(position).score;
将返回位置可以是任意数字的位置元素
答案 2 :(得分:1)
如果您想要更复杂的方法,可以查看std::partition
函数。
std :: partition接受一个容器并将其分为两部分。
std::vector<MyOwnClass> v(100);
// fill vector with stuff. Find n-th element.
auto mid = v[somwhere_in_the_middle];
auto p = std::partition(v.begin(), v.end(),
[mid](MyOwnClass v){ return v.score < mid.score; } );
每个大于p
的元素都位于p
的右侧。较小的是左边。
如果您正在寻找第二大,只要v.end() - p
的距离足够大,就会向右移动。
此方法基于快速排序的想法称为快速选择,详细信息请参见How to find the kth largest element in an unsorted array of length n in O(n)?。
这当然已经实现为std::nth_element
,可以用作
std::nth_element(v.begin(), v.begin()+5, v.end(), std::greater<int>());
获得第6位的第6大元素。
答案 3 :(得分:0)
您可以通过获取已有的max
元素并在其中找到std::max_element()
并获取这两个值的std::max()
来完成此操作:
struct MyOwnClass
{
int score = 0;
MyOwnClass(int s): score(s) {}
};
vector<MyOwnClass> scores = {{4}, {2}, {7}, {9}, {3}};
int main()
{
// we need this more than once
auto compare = [] (const MyOwnClass &a, const MyOwnClass &b)
{
return a.score < b.score; // I am not sure how this line works
};
auto max = std::max_element(scores.begin(), scores.end(), compare);
std::cout << "max: " << max->score << '\n';
// call std::max_element() twice with ranges either side of the max element
// and get the std::max() of those values
auto next_max = std::max(std::max_element(scores.begin(), max, compare)->score
, std::max_element(max + 1, scores.end(), compare)->score);
std::cout << "next max: " << next_max << '\n';
}
注意:如果你想获得第三个或第四个元素,这种技术是一种收益递减的技术,可能最好做一个std::sort()
。