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