在C ++中获得中等价值

时间:2014-05-04 10:47:06

标签: c++ algorithm c++11 max min

考虑三个值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));

6 个答案:

答案 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) ...

开始
  1. 如果它返回z ,我们找到了关系: max(x,y)> ž。然后表达式求值为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)< z ,那么z确实是中位数(如 min(x,y)< z< max(x,y))。

  2. 如果它返回x ,那么我们 x< z y< ž。表达式的计算结果为:max(min(x,y),x)。由于max(x,y)求值为x,min(x,y)求值为y。获得关系 z> x> ÿ。我们返回x和y的最大值(因为表达式变为max(y,x)),它是x,也是中位数。 (注意y的证明是对称的)

  3. 证明结尾


    旧证明 - 注意它不完整(直接):

    不失一般性: 假设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;
}