經常遇到一個事情,就是獲取一個圖片中所有像素值的最大和最小 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