单元测试
//median返回类型
using result_type
= typename MedianHolder<int>::return_type;
//自定义矩阵类型
template <std::size_t N>
using integer_matrix
= std::array<std::initializer_list<int>, N>;
int main(void){
//测试数据组
integer_matrix<5> test = {{
{9, 6, 3, 8, 4, 7, 1, 2, 5, 0},
{2, 5, 8, 3, 6, 7, 4, 9, 0, 1},
{4, 8, 2, 3, 9, 0, 5, 1, 7, 6},
{3, 9, 7, 8, 5, 2, 1, 6, 4, 0},
{1, 7, 2, 6, 5, 8, 0, 4, 3, 9}
}};
for(auto& row : test){
//先展示数字序列
std::copy(row.begin(), row.end(), std::ostream_iterator<int>(std::cout, "|"));
std::endl(std::cout);
//输出中位数(奇数一位,偶数两位)
std::cout << "Median:\t";
result_type res = MedianHolder<int>(row);
if(res.first) std::cout << *res.first << ' ';
std::cout << res.second << "\n\n";
}
return 0;
}
#include <queue>
#include <iterator>
#include <functional>
#include <algorithm>
#include <deque>
#include <concepts>
#include <initializer_list>
#include <iostream>
#include <array>
template <class Ty,
class Lesser = std::less<Ty>>
requires std::strict_weak_order<Lesser, Ty, Ty> //可自定义可调用拟序谓词
class MedianHolder{
static_assert(std::same_as<typename std::decay<Ty>::type, Ty>);
//静态断言:Ty should be non-volatile & non-const
static_assert(std::assignable_from<Ty&, Ty>
|| std::assignable_from<const Ty&, Ty>);
//静态断言:const_assignable自然可赋值
public:
struct Greater
: public std::binary_function<Ty, Ty, bool>{
constexpr bool
operator()(const Ty& x, const Ty& y) const
{ return !Lesser{}(x, y); }
};
//大于等于谓词
protected:
//对顶堆 分别维护左区间和右区间
std::priority_queue<Ty, std::deque<Ty>, Lesser> Left;
std::priority_queue<Ty, std::deque<Ty>, Greater> Right;
private:
std::size_t dSize {0U};
public:
constexpr MedianHolder(void) noexcept = default;
MedianHolder& operator=(const MedianHolder&) = default;
MedianHolder& operator=(MedianHolder&&) noexcept = default;
//宽类型转换构造 初始化列表一次性批量构造
template <typename Up>
inline MedianHolder(std::initializer_list<Up> ilist) {
for(auto& t : ilist) push(t);
}
//一个元素push,宽类型检查
template <class Up,
class = typename
std::enable_if<
std::convertible_to<Up, Ty>>::type>
requires (requires(Ty x, Up y){
{Lesser{}(x, y)} -> std::convertible_to<bool>;
})
void push( const Up& x){
if(Right.empty() || Greater{}(x, Right.top())){
Right.push(x);
if(Left.size() < Right.size() + 1U){
Left.push(Right.top());
Right.pop();
}
}else{
Left.push(x);
if(Left.size() > Right.size()){
Right.push(Left.top());
Left.pop();
}
}
}
//形参包展开,批量push接口
template <class... Args>
constexpr void batch_push(Args&&... args)
noexcept((noexcept(push(args))&&...)){
(((void)push(args)), ...);
}
//公开返回类型
using return_type = std::pair<std::optional<Ty>, Ty>;
//返回中位数
constexpr inline return_type
median(void) const{
return {
Right.size() > Left.size()
? std::nullopt
: std::make_optional(Left.top())
, Right.top()};
}
//隐式转换,方便输出比较等操作
constexpr operator return_type() const{
return std::move(median());
}
};
//推导指引,构造时可以不指定模板参数
template <class Up>
MedianHolder(std::initializer_list<Up> ilist)
->MedianHolder<Up>;