简体   繁体   English

std :: max_element用于第二大元素?

[英]std::max_element for second largest element?

The STL provides std::max_element to find the largest element in an iterable, eg like this: STL提供std::max_element来查找可迭代的最大元素,例如:

std::vector<float>::const_iterator max = 
  std::max_element(obj.pt()->begin(), obj.pt()->end());
return std::distance(obj.pt()->begin(), max);

Is there also something to get an iterator for the n-th largest element? 还有第n个最大元素可以得到迭代器的东西吗?

(Note that max_element returns an iterator and this is actually important: Rather than for the value itself, I am looking for the position of the n-th largest element within the iterable.) (请注意, max_element返回一个迭代器,这实际上很重要:我不是在寻找值本身,而是在迭代器中寻找第n个最大元素的位置。)

If you are specifically interested in the second-largest element, you can do a simple scan of the array in which most elements require a single comparison: 如果您对第二大元素特别感兴趣,则可以对数组进行简单扫描,其中大多数元素需要进行一次比较:

float second_largest_element(std::vector<float> vec) {
  float m2, m1;
  /* Check to make sure that vec has at least 2 elements!! */
  std::tie(m2, m1) = std::minmax(vec[0], vec[1]);
  for (auto it = vec.begin() + 2, limit = vec.end();
       it != limit;
       ++it)
    if (*it > m2) std::tie(m2, m1) = std::minmax(*it, m1);
  return m2;
}

Getting the index of (or an iterator to) the second largest element is very similar, although std::minmax is less useful. 尽管std::minmax不太有用,但获取第二大元素的索引(或对其进行迭代)非常相似。 Here's a very sloppy example: 这是一个很草率的例子:

template<typename T>
typename T::iterator second_largest(T& container) {
  using iterator = typename T::iterator;
  iterator limit = container.end();
  iterator it = container.begin();
  if (it != limit) {
    iterator first = it++;
    if (it != limit) {
      iterator second = it++;
      if (*first < *second) std::swap(first, second);
      for (; it != limit; ++it) {
        if (*second < *it) {
          if (*first < *it) { second = first; first = it; }
          else              { second = it; }
        }
      }
      return second;
    }
    return first;
  }
  return it;
}

You could also consider using std::accumulate to scan the array, although the explicit for loop is not complicated. 您也可以考虑使用std::accumulate扫描阵列,尽管显式的for循环并不复杂。

As Dyp mentioned in comment, if you are fine to alter the order of elements within your vector you can use std::nth_element as follows. 正如Dyp在评论中提到的那样,如果您可以更改vector中元素的顺序,则可以如下使用std::nth_element On top if you use find again over vector you will get original position of the nth element from vector . 最重要的是,如果再次在vector使用find ,则会从vector获得第n个元素的原始位置。 Since nth_element modifies the positions, you have to keep a local copy of it before doing nth_element operation over vector. 由于nth_element修改了位置,因此您必须在对向量执行nth_element操作之前保留其本地副本。

2nd largest element: 第二大元素:

std::vector<float> orig_vec=obj.pt;

std::nth_element(obj.pt().begin(), obj.pt().begin()+1, 
                  obj.pt().end(), std::greater<float>());
float 2nd= *(obj.pt().begin()+1);
auto it=std::find(orig_vec.begin(), orig_vec.end(), 2nd);

nth largest element: 第n个最大元素:

  std::nth_element(obj.pt().begin(), obj.pt().begin()+n-1,
    obj.pt().end(), std::greater<float>());
  float nth= *(obj.pt().begin()+n-1);

 auto it=std::find(orig_vec.begin(), orig_vec.end(), nth)

This is a trivial algorithm to implement in linear time. 这是在线性时间内实现的简单算法。 The naive approach would be to compare the first two values, and select them as the max and second largest values. 天真的方法是比较前两个值,然后选择它们作为最大值和第二个最大值。 Then you need to iterate over the other elements comparing each new element with both of them and adjusting your current max and second largest values. 然后,您需要遍历其他元素,将每个新元素与两个元素进行比较,并调整当前的最大值和第二最大值。 For most use cases that is probably more than enough. 对于大多数用例来说,这可能绰绰有余。 If you really care about performance (as in you care a lot ) you will need to think what values you want to compare to minimize the number of comparisons. 如果你真的关心性能(如在你多多关照 ),你需要考虑你想比较,以尽量减少比较的次数什么样的价值观。

Also note that float (floating point in general) have quirks... you might get funny values if your input contains NaN or infinite values. 还要注意, float (通常是float )具有怪癖...如果您的输入包含NaN或无限值,则可能会得到有趣的值。

It took me a while to find a solution, because I worked with const vector (so I can't use nth_element) and copy would be just wasting (especially, when vector is holding a bigger structures). 我花了一段时间才找到解决方案,因为我使用了const vector(因此我不能使用nth_element),而复制只会浪费掉(特别是当vector具有更大的结构时)。 So I came with this: 所以我来了:

// Find 1st max
auto max1 = max_element(vec.begin(), vec.end());
if (max1 != vec.end())
    // Use max1

// Find 2nd max. Split the vector into 2 parts, find max and merge results
auto max2Beg = max_element(vec.begin(), max1);
auto max2End = max_element(max1 + 1, vec.end());
auto max2 = max2Beg == max1 ? max2End :
            max2End == vec.end() ? max2Beg : max(max2Beg, max2End);
if (max2 != max1 && max2 != vec.end())
    // Use max2

max_element() method can be used to get second largest element by passing lambda function which compares the element with the previously found largest element and if it is equal to the largest element then it'll simply skip that element. 通过传递lambda函数可以将max_element()方法用于获取第二大元素,该函数会将元素与先前找到的最大元素进行比较,如果它等于最大元素,则将直接跳过该元素。

auto largest = max_element(vec.begin(), vec.end());
auto secondLargest = max_element(vec.begin(), vec.end(),
                                 [&largest](unsigned long &a, unsigned long &b) {
                                     return ((b != (*largest)) && (a < b));
                                 });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM