考虑三个值x, y, z
。
获得中间值的公式是什么(不是平均值,而是既不是min
也不是max
的值?
const double min = std::min(x, std::min(y, z));
const double mid = /* what formula here ? */
const double max = std::max(x, std::max(y, z));
答案 0 :(得分:13)
以对称的方式一次性找到所有三个:
min = x; med = y; max = z;
if (min > med) std::swap(min, med);
if (med > max) std::swap(med, max);
if (min > med) std::swap(min, med);
答案 1 :(得分:12)
这似乎是作弊,但是:x + y + z - min - max
答案 2 :(得分:12)
this link的答案在评论中分享:
const double mid = std::max(std::min(x,y),std::min(std::max(x,y),z));
编辑 - 正如艾伦指出的那样,我错过了一个案例。我现在给出了一个更直观的证据。
直接证明:关于x和y,不失一般性。
从最里面的表达式min(max(x,y),z)
...
max(min(x,y),z)
。通过这个,我们能够确定min(x,y)和z之间的关系。如果min(x,y)> z ,则z小于x和y两者(因为关系变为: max(x,y)> min(x,y)> z )。因此,min(x,y)确实是中位数并且max(min(x,y),z)
返回那个。
max(min(x,y),x)
。由于max(x,y)求值为x,min(x,y)求值为y。获得关系 z> x> ÿ。我们返回x和y的最大值(因为表达式变为max(y,x)
),它是x,也是中位数。 (注意y的证明是对称的)
证明结尾
旧证明 - 注意它不完整(直接):
不失一般性:
假设x> y> z
最小x和y是y。并且min(x和y的最大值)和z是z
y和z的最大值是y,即中位数。
假设x = y> ž
x和y的最小值是x。并且min(x和y的最大值是x)并且z是z
上述两个中的最大值是x,即中位数。
假设x> y = z
最小x和y是y。并且min(x和y的最大值是x)并且z是z
上述两个中的最大值是y,即中位数。
最后,假设x = y = z
这三个数字中的任何一个都是中位数。并且使用的公式将返回一些数字。
答案 3 :(得分:4)
这比Alan的伎俩有点丑陋,但它不会导致溢出,也不会导致数字错误,等等:
int x, y, z, median;
...
if (x <= y && y <= z || y >= z && y <= x) median = y;
else if (y <= x && x <= z || x >= z && x <= y) median = x;
else median = z;
算法很简单:
检查x是否在y和z之间,如果是,那就是它。
检查y是否在x和z之间,如果是,那就是它。
必须是z,因为它既不是x,也不是y。
=============================================== ==
如果你有三个以上的元素,你也可以更灵活地进行排序。
//或xor实现,无所谓......
void myswap(int * a,int * b) { int temp = * b; * b = * a; * a = temp; }
int x, y, z;
// Initialize them
int min = x;
int med = y;
int max = z;
// you could also use std::swap here if it does not have to be C compatible
// In that case, you could just pass the variables without the address operator.
if (min > med) myswap(&min, &med);
if (med > max) myswap(&med, &max);
if (min > med) myswap(&min, &med);
答案 4 :(得分:3)
艾伦的“作弊”的一种变体,(有时甚至有时)防止溢出:
#include <iostream>
#include <algorithm>
using namespace std;
int main(int argc, char *argv[]) {
double a = 1e308;
double b = 6e306;
double c = 7.5e18;
double mn = min(a,min(b,c));
double mx = max(a,max(b,c));
double avg = mn + (mx-mn)*0.5;
double mid = a - avg + b - avg + c;
cout << mid << endl;
}
输出:
6e+306
它利用二进制搜索中经常使用的avg-formula来防止溢出:
两个值的平均值可以计算为low + (high-low)/2
但是,它仅适用于正值。可能的后备包括Alan的答案,或简单地(x+y)/2
进行平均计算。
请注意,双精度在此处起作用,可能会导致mid
- 计算中出现问题。它虽然对正整数很有效:)
答案 5 :(得分:3)
执行此操作的最佳方法是使用通用中值函数模板。不需要复制,交换或数学运算。
template <typename T>
const T& median(const T& a, const T& b, const T& c)
{
if (a < b)
if (b < c)
return b;
else if (a < c)
return c;
else
return a;
else if (a < c)
return a;
else if (b < c)
return c;
else
return b;
}