具有最大N个相等元素的c ++向量'位置

时间:2016-01-29 06:13:59

标签: c++ vector max equals

我可以使用STL中的预定义函数获取最多N个元素(相等的最大元素)的位置吗?

我想到的解决方案是:

vector<int> maxN(vector<int> original){
    vector<int> result;
    auto pt = max_element(original.begin(),original.end());
    int max = *pt;
    while(*pt == max){
        result.push_back(distance(original.begin(),pt));
        *pt = 0;//assumed that all the elements in original are greater than 0
        pt = max_element(original.begin(),original.end());
    }
     return result;
}

必须有一种更优雅的方式来做到这一点。

4 个答案:

答案 0 :(得分:3)

这取决于您的确切要求:

std::max_element为您提供最大元素。 std::copy_if可用于复制所有等于最大值的元素(如果需要,可以限制最大数量,例如使用lambda)。

std::nth_element对范围(例如您的向量)进行部分排序,使得前n个条目等于或小于后面的任何内容。前n个元素不是自己排序的。它不是一个稳定的分区。

std::partial_sort为您提供相同的内容,但前n个元素已排序。同样,不是一个稳定的分区/排序。

如果您需要稳定选择前n个元素并且希望它们稳定排序,请将std::nth_element + std::stable_partition + std::stable_sort合并。

答案 1 :(得分:2)

找到max元素后,在向量上进行另一次线性传递,找到所有匹配元素。这样做时不需要设置为0。原始向量按值传递,因此调用者未看到设置为0。这使得实现非常明确:

vector<int> maxN(vector<int> original){
    vector<int> result;
    if (original.empty()) return result;
    const int max = *(max_element(original.begin(), original.end()));
    for (int i = 0; i < original.size(); ++i) {
        if (original[i] == max) result.push_back(i);
    }
    return result;
}

实现清晰且可维护的代码比尝试从C ++库中提取最大重用更为重要。

如果你的目标是不使用传入的原始向量的显式循环,但使用一些标准的C ++模板算法,我建议创建一个帮助迭代器来帮助你恢复索引。

struct indexer {
    int i_;
    indexer (int i = 0) : i_(i) {}
    indexer & operator ++ () { ++i_; return *this; }
    indexer operator ++ (int) { ++i_; return i_ - 1; }
    int operator * () const { return i_; }
    bool operator != (indexer rhs) const { return i_ != rhs.i_; }
    //... whatever else is required for copy_if
};

然后,您可以使用简单的lambda和后插入迭代器调用copy_if

copy_if(indexer(), indexer(original.size()), back_inserter(result),
        [&](int i) -> bool { return original[i] == max; });

然而,这比上面提到的简单循环更加模糊。

答案 2 :(得分:0)

作为变体(可以查看cpp.sh

#include <iostream>
#include <vector>

int main ()
{
    std::vector<int>elems = {10, 20, 10, 30, 5, 30, 8, 30, 18, 12};
    for(size_t i=0; i<elems.size()-1; i++)
    {
        if(elems[i+1] > elems[i]) { elems.erase(elems.begin()+i); i=-1;}
            else if(elems[i+1] < elems[i]) { elems.erase(elems.begin()+i+1); i=-1;}            
    }

    return 0;
}

答案 3 :(得分:0)

你可以使用索引装饰你的原文,采用第N个元素方法,再次剥离索引(在cpp.sh上测试):

template<typename T, typename less = std::greater<T>>
std::vector<int> max_indices(
     int N,
     const std::vector<T> &original,
     less predicate = less())
{
    auto decorated = with_indices(original);

    // the gist of the problem
    const auto nth = std::next(begin(decorated), N);
    std::nth_element(begin(decorated), nth, end(decorated),
                     with_indices(predicate));
    std::sort(begin(decorated), nth,
                     with_indices(predicate));        
    decorated.erase(nth, end(decorated));

    return indices(decorated);
}


int main()
{
    std::vector<int> values{ {1, 2, 3 , 4, 5, 6, 7, 8, 9, 10} };

    auto m = max_indices(4, values);
    assert(4u == m.size());
    assert(9 == m[0]);
    assert(8 == m[1]);
    assert(7 == m[2]);
    assert(6 == m[3]);

    return 0;
}

这些功能在装饰/未装饰的地方:

template<typename T>
std::vector<std::pair<T, int>> with_indices(const std::vector<T> &original)
{
    std::vector< std::pair<T, int> > decorated;
    std::transform(begin(original), end(original), std::back_inserter(decorated),
        [index = 0](T t) mutable {
        return std::make_pair(t, index++);
    });
    return decorated;
}

template<typename T>
std::vector<int> indices(const std::vector<std::pair<T, int>> &original)
{
    std::vector<int> undecorated;
    std::transform(begin(original), end(original), std::back_inserter(undecorated),
        [](auto p) mutable {
        return p.second;
    });
    return undecorated;
}

template<typename Function>
auto with_indices(Function f)
{
    return [&](auto... args) {
        return f(args.first...);
    };
}