我可以使用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;
}
必须有一种更优雅的方式来做到这一点。
答案 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...);
};
}