在对象c ++的向量中查找字段的第二个(或n)最高值

时间:2014-11-13 16:41:37

标签: c++ object vector iterator field

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的方式,我不确定它是否可以用来找到第二大。

哦,最后,我宁愿不从向量中弹出最高值,找到新的最大值(原始向量中的第二高值)并添加一些逻辑来恢复原始版本。好吧,如果我必须,我会这样做,但可能会有一些迭代器属性或其他我不知道的东西......

4 个答案:

答案 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];
}

Live example

注意:由于来自莫斯科的 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()