C++ 获取C+中的中值+;
考虑三个值C++ 获取C+中的中值+;,c++,algorithm,c++11,max,min,C++,Algorithm,C++11,Max,Min,考虑三个值x、y、z 得到中间值(不是平均值,而是既不是min也不是max的值)的公式是什么 这看起来像是作弊,但是:x+y+z-min-max这比艾伦的诡计要难看一点,但它不会导致溢出,也不会导致数字错误,等等: int x, y, z, median; ... if (x <= y && y <= z || y >= z && y <= x) median = y; else if (y <= x && x &l
x、y、z
得到中间值(不是平均值,而是既不是min
也不是max
的值)的公式是什么
这看起来像是作弊,但是:
x+y+z-min-max
这比艾伦的诡计要难看一点,但它不会导致溢出,也不会导致数字错误,等等:
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;
要同时以对称方式找到所有三个:
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);
艾伦“欺骗”的一种变体,它(有时)可以防止溢出:
#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;
}
它利用二进制搜索中常用的avg公式来防止溢出:
#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;
}
两个值的平均值可计算为low+(high-low)/2
但是,它只适用于正值。可能的备选方案包括Alan的答案,或者简单地(x+y)/2
进行平均值计算
请注意,双精度在这里起作用,可能会导致mid
-计算中出现问题。它对正整数非常有效:)注释中共享的答案:
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)
返回该值。如果min(x,y)
max(min(x,y),x)
。由于max(x,y)计算为x,min(x,y)计算为y。获取关系z>x>y。我们返回x和y的最大值(表达式变为max(y,x)
),即x和中位数。(注意y的证明是对称的)
旧校样-注意它不完整(直接): 在不丧失一般性的情况下: 假设x>y>z
x和y的最小值是y。最小值(x和y的最大值),z是z。
y和z的最大值为y,即中间值 假设x=y>z
x和y的最小值等于x。最小值(x和y的最大值为x)和z为z.
以上两项的最大值为x,即中值 假设x>y=z
x和y的最小值是y。最小值(x和y的最大值为x)和z为z.
以上两项的最大值为y,即中值 最后,假设x=y=z
三个数字中的任何一个都是中位数,使用的公式将返回一些数字。最好的方法是使用通用的中位数函数模板。不需要复制、交换或数学运算
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;
}
模板
常数T和中间带(常数T&a、常数T&b、常数T&c)
{
if(a
也许没有一个简洁的对称公式?@AbhishekBansal如果它们都相等呢?如果只有两个相等呢?仅供参考,这称为中位数。随便挑一个。然后,你的应用程序将工作1/3的时间,这比我当前的应用程序要多得多。顺便说一句,在C++11中,min
可以重写std::min({x,y,z})
。我喜欢它。唯一的问题是溢出。@keyser:是的,所以也值得发布一个不同的答案,以防万一。此外,这不一定返回变量,只返回值。@Laszlo True(尽管可以说这是min和max的错误特性)。因为我们没有参考答案,所以没关系。你可以在没有mix和max的情况下获得med,因此它们的限制是不必要的。据我所知,至少有两个选项,或者不使用min和max。如果您想要全部三个选项(min、mid、max),那么对列表进行排序可能是最好的。一次比较和交换以获得前两个的顺序,然后最多进行两次测试以确定其他两个的顺序。是的,尽管这是一个特定的解决方案,而且此解决方案也可以在C中工作,而不像std::swapPTrue-虽然求中值(或n_最大值)的一般算法是基于快速排序的,但跳过了不必要的工作。@AlanStokes:当然,我同意。这个版本是为了可读性和可理解性而优化的,而那个版本是为了效率和灵活性而优化的。这里没有效率问题,OP似乎询问了三个值,但是,我认为这两个值都是有效的。但是,是的,排序对3个以上的元素也起着温和的作用;只需要确定奇数。@AlanStokes:更新了一个与C兼容的交换排序版本(即气泡排序),以防万一:这不是一种泡沫排序吗?@AbhishekBansal这确实是一种泡沫排序。@OliCharlesworth:我是知道的。我不想问这个:那又怎样?我不能说它在C语言中不起作用?你认为“只是说”是什么意思@LaszloPapp:只是不确定你之前评论的目的是什么,仅此而已(这段代码在Java中也不起作用!)。(例如,这很容易被视为对标签的误读。)@OliCharlesworth:“仅仅说”通常意味着这不是一件大事,而且此人知道具体情况。在谈论兼容性时,比较C++中的java和C是奇怪的,我必须这么说,尤其是考虑到我的答案表明了一小时前的意图。Fwiw,我甚至对答案(以及问题)投了更高的票,尽管我有另一个答案
const double mid = std::max(std::min(x,y),std::min(std::max(x,y),z));
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;
}