中位数计算必须先排序,否则结果一定错;c++标准库无直接求未排序数据中位数函数,小数据量时用std::nth_element或std::partial_sort需谨慎。

中位数计算必须先排序,否则结果一定错
中位数定义依赖于有序序列,C++ 标准库不提供现成的“未排序数据求中位数”函数。直接对 std::vector 调用 std::nth_element 或 std::partial_sort 看似省事,但要注意:当数据量小(比如 std::sort 反而更稳、更易读。
- 对偶数个元素,中位数是中间两个数的平均值(注意类型:若用
int存储会导致截断) - 对奇数个元素,中位数是严格位于中间位置的元素(索引为
size() / 2,整除) - 别在原容器上盲目调用
std::sort——如果原始顺序需要保留,先拷贝一份
用 std::sort + size() / 2 是最稳妥的通用解法
这是工程中推荐的写法:清晰、可调试、无边界风险。关键点在于索引计算和类型转换。
std::vector<double> data = {3.5, 1.2, 4.8, 2.1};
std::sort(data.begin(), data.end());
size_t n = data.size();
double median;
if (n % 2 == 0) {
median = (data[n/2 - 1] + data[n/2]) / 2.0;
} else {
median = data[n/2];
}</double>
- 用
double存数据或强转中间结果,避免整数除法丢失精度 -
n/2 - 1和n/2是偶数情况下的两个中心索引(如 size=4 → 索引 1 和 2) - 不要写成
(data[(n-1)/2] + data[n/2]) / 2.0——虽然数学等价,但可读性差且易在无符号类型下出错
std::nth_element 能更快但只适合单次、大数据量场景
当数据极大(比如百万级)且只求一次中位数,std::nth_element 平均时间复杂度 O(n),比 std::sort 的 O(n log n) 更优。但它不保证整体有序,仅确保第 k 位正确,且会修改原容器。
- 对偶数个元素,它无法直接给出两个中间值——你得调用两次,或退回到部分排序
- 调用后,
data[k]是第 k+1 小的数(k 从 0 开始),所以中位索引仍是n/2(奇数)或需额外处理(偶数) - 示例:求奇数长度中位数可写
std::nth_element(data.begin(), data.begin() + n/2, data.end()); median = data[n/2]; - 实际项目中,除非 profiler 明确指出排序成了瓶颈,否则别过早优化
空容器或单元素容器必须显式检查
几乎所有线上 bug 都出在边界——空 vector 调用 begin() 后 sort 不崩溃,但取 data[0] 会 UB;单元素时 n/2 是 0,没问题,但逻辑上仍建议统一 guard。
- 空容器应抛异常或返回
std::optional<double></double>(C++17+) - 别依赖“用户不会传空数据”——输入来自文件、网络或用户交互时,空是常态
- 简单防御写法:
if (data.empty()) throw std::runtime_error("empty data");
中位数看似简单,但类型、边界、排序副作用这三点,任一疏忽都会导致静默错误或线上异常。尤其在模板泛型代码里,T 是 int 还是 float 直接决定要不要写 / 2.0。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











