从矢量中获取n个最佳元素?

时间:2015-03-27 20:43:38

标签: c++ vector data-structures stl

我有一个结构向量,我为此重载了所有比较运算符。我不知道编译时结构的大小。

在向量中检索n个最佳元素(其中"最佳"可以是最小值还是最大值)的禁区方法是什么?我知道max_element和min_element但它们只返回一个元素。我宁愿不循环n次,检索最佳元素,删除它然后获取下一个元素。这种方法似乎太慢了。

感谢。

6 个答案:

答案 0 :(得分:4)

您可以使用std::nth_element,将最小的n元素移动到范围中的第一个n位置(注意这些n元素的相对排序是未定义)。

std::vector<T> objects;
std::nth_element( objects.begin(), objects.begin() + n, objects.end() );

// Now the range [objects.begin(), objects.begin() + n) contains the lowest n elements
// Obviously n must be <= objects.size()

当你编写时,你不知道编译时结构的大小,我假设你有一个多态对象的集合,你有一个指针向量而不是元素。没什么大不了的,你仍然可以将std::nth_element与lambda一起使用。

std::vector<T*> objects;
std::nth_element( objects.begin(),
                  objects.begin() + n,
                  objects.end(),
                  [](const T * lhs, const T * rhs)
                  {
                      return (*lhs) < (*rhs); // Or (*lhs) > (*rhs) for the greatest n elements
                  });

答案 1 :(得分:1)

对它进行排序,然后取n个元素。

struct Foo { };
std::vector<Foo> v = { Foo(), Foo(), Foo() };
std::sort(v.begin(), v.end());

std::vector<Foo> v_best(v.begin(), v.begin() + n); //where n is your best count

答案 2 :(得分:1)

另一种方法,而不是蛮力排序和第一步:设置一个大小为n的临时容器,并使用原始向量的第一个n元素对其进行初始化(例如,大小为N。对该临时矢量进行排序。

接下来遍历原始向量并插入元素(使用std::lower_bound),只要它们大于已排序容器的当前最小值(同时抛出当前最小值)。这应首先取O(n log n + N)而不是O(N log N)渐近,但更重要的是,常数前因子也可能小得多。

答案 3 :(得分:0)

如果要检索n个最小元素,请按升序排序vector

如果要检索n个最大元素,请按降序排序vector

然后,

  1. 获取两个迭代器。

    start = v.begin();
    end = start + n;
    
  2. startend进行迭代,但不包括end

答案 4 :(得分:0)

此处的其他答案有效,但您也可以使用copy_if

std::vector<int> vec{ 1, 5, 7, 9, 3, 6, 8, 4, 2 };

std::vector<int> odd;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(odd), [](int a){ return a % 2 == 1; });
std::vector<int> low;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(low), [](int a){ return a <= 3; });
std::vector<int> high;
std::copy_if(vec.begin(), vec.end(), std::back_inserter(high), [](int a){ return a >= 7; });

如果您需要删除匹配的数据,还有remove_copy_if

答案 5 :(得分:0)

我建议你一个解决方案既不修改也不复制矢量

所以我假设原始矢量非常大,你仍然需要原始顺序的数据用于其他目的

template <typename T>
set<T> best_n2(vector<T>& v, size_t n)
{
    set<int> u;          // the result is a sorted set
    int i = 0;
    for (auto x : v) {   // fill the N first elements
        if (i++ < n) {
            u.insert(x);
        }
        else if (x > *u.begin()) {  // then get rid of the smallest if necessray
            u.erase(*u.begin()); 
            u.insert(x);
        }
    }
    return u;
}

如果你可以修改原始矢量,我选择szulack的解决方案。我没有提出建议,因为他的打字速度比我快得多; - )