C++ 获取序列最大(或最小)的 N 个元素

经常遇到一个事情,就是获取一个图片中所有像素值的最大和最小 2% 的值,所以封装了一个 LimitArray 的类,用于把一个序列中最大(或最小)的 N 个值给提取出来。

代码如下:

#include <iostream>
#include <vector>
#include <array>
#include <limits>
#include <type_traits>
#include <algorithm>
#include <iterator>


/// <summary>
/// 极限值数组
/// 用于获取序列的最小或者最大的多个值.
/// </summary>
/// <typeparam name="T">数据类型</typeparam>
template <typename T,size_t _size,bool _minimum>
class LimitArray:public std::array<T,_size> {
    static_assert(std::is_arithmetic<T>::value,
        "template parameter must arithmetic types");
    static_assert(_size > 1, "please use min_element or max_element");
public:
    LimitArray()
    {
        if (_minimum) {
            this->fill(std::numeric_limits<T>::max());
        }
        else {
            this->fill(std::numeric_limits<T>::lowest());
        }
    }
    /// <summary>
    /// 添加一个值 value
    /// 如果获取小值,且 value < fornt 则所有元素后移一位,弹出 back, value作为首元素
    /// 如果获取大值,且 value > back 则所有元素前移一位,弹出 front, value作为末元素
    /// </summary>
    /// <param name="value"></param>
    inline void push(T value)
    {
        if (_minimum) {
            // 留小不留大,如果比当前最大值都大,就不用继续了
            if (value >= this->back()) { return; }
            // 下面的操作就是,把最大的元素移除,把 value 插入合适位置
            // 查找合适的插入点;第一个大于 value 的元素的迭代器
            auto iter = std::upper_bound(this->begin(), this->end(), value);
            // 移动 [插入点,倒数第二个] 数据往后一位
            // 注意,参数是半闭半开区间 ,第三个参数是目标序列的最后一个的后一个
            std::move_backward(iter, this->end() - 1, this->end());
            *iter = value;
        }
        else {
            // 留大不留小
            if (value <= this->front()) { return; }
            // 查找合适的插入点;第一个不小于 value 的元素的迭代器的前一个
            auto iter = std::lower_bound(this->begin(), this->end(), value) - 1;
            // 移动 [第二个,插入点] 数据往前一位
            std::move(this->begin() + 1, iter+1, this->begin());
            *iter = value;
        }
    }
};

// 简单测试一下
int main()
{
  std::vector<int> v = {1,3,2,6,4,7,5,0,9,8};
  LimitArray<int,7,true> la1;
  LimitArray<int,2,false> la2;
  for(size_t i=0;i<v.size();++i){
    la1.push(v[i]);
    la2.push(v[i]);
  }
  std::copy(la1.begin(), la1.end(),
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
    std::copy(la2.begin(), la2.end(),
              std::ostream_iterator<int>(std::cout, " "));
    std::cout << '\n';
  return 0;
}

运行输出如下:

0 1 2 3 4 5 6 
8 9

posted @ 2020-07-27 21:12  乌合之众  阅读(1333)  评论(0编辑  收藏  举报
clear