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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM