截至目前,我的功能找到3个数字的中位数并对它们进行排序,但它总是进行三次比较。我想我可以在某处使用嵌套的if语句,这样有时我的函数只会进行两次比较。
int median_of_3(int list[], int p, int r)
{
int median = (p + r) / 2;
if(list[p] > list[r])
exchange(list, p, r);
if(list[p] > list[median])
exchange(list, p, median);
if(list[r] > list[median])
exchange(list, r, median);
comparisons+=3; // 3 comparisons for each call to median_of_3
return list[r];
}
我不确定我在哪里可以看到嵌套的if语句。
答案 0 :(得分:22)
如果您只需要中值,这里是基于最小/最大运算符的无分支解决方案:
median = max(min(a,b), min(max(a,b),c));
英特尔CPU具有SSE最小/最大向量指令,因此根据您或您的编译器进行向量化的能力,这可以非常快速地运行。
答案 1 :(得分:2)
int m = (p + r) / 2;
if (list[p] < list[m])
if (list[p] >= list[r])
return list[p];
else if (list[m] < list[r])
return list[m];
else
if (list[p] < list[r])
return list[p];
return list[r];
答案 2 :(得分:2)
如果我们允许额外的操作,我们最多可以使用2次比较来找到中位数。 诀窍是使用exclusive或查找三个数字之间的关系。
void median3(int A[], int p, int r)
{
int m = (p+r)/2;
/* let a, b, c be the numbers to be compared */
int a = A[p], b = A[m], c = A[r];
int e = a-b;
int f = a-c;
if ((e^f) < 0) {
med_comparisons += 1;
/* a is the median with 1 comparison */
A[m] = a;
/* b < a < c ? */
if (b < c) /* b < a < c */ { A[p] = b, A[r] = c; }
else /* c < a < b */ { A[p] = c, A[r] = b; }
comparisons += 2;
} else {
med_comparisons += 2;
int g = b-c;
if ((e^g) < 0) {
/* c is the median with 2 comparisons */
A[m] = c;
/* a < c < b ? */
if (a < b) /* a < c < b */ { A[p] = a, A[r] = b; }
else /* b < c < a */ { A[p] = b, A[r] = a; }
} else {
/* b is the median with 2 comparisons */
A[m] = b;
/* c < b < a ? */
if (a > c) /* c < b < a */ { A[p] = c; A[r] = a; }
else /* a < b < c */ { /* do nothing */ }
}
comparisons += 3;
}
}
第一个异或或(e ^ f)是找出(a-b)和(a-c)之间符号位的差异。
如果他们有不同的符号位,那么a是中位数。否则,a是最小值或最大值。在这种情况下,我们需要第二个独占或(e ^ g)。
同样,我们将找出(a-b)和(b-c)之间符号位的差异。 如果他们有不同的符号位,一个案例是&gt; b&amp;&amp; b&lt; c。在这种情况下,我们还得到 a&gt; c ,因为在这种情况下 a是最大值。所以我们有 a&gt; c>湾强> 另一种情况是 a&lt; b&amp;&amp; b> c&amp;&amp; a&lt; ç即可。所以我们有 a&lt; c&lt; B'/强>; 在这两种情况下,c是中位数。
如果(ab)且(bc)具有相同的符号位,则b为中位数使用与上面类似的参数。实验表明,随机输入需要 1.667比较来找出中位数和一个额外的比较来获得订单。
答案 3 :(得分:1)
要对3个项目进行排序,您需要进行3次比较。
要偶然找到中间的一个,你需要2。
要准确找到中间的,你需要平均2 + 2 / 3~ = 2.67(均匀分布的随机数据)
if (a<b) {
// partial order = a,b
if (b<c) { } // 2 comparisons: order is a,b,c
else { // order is a,c,b or c,a,b
if (a<c) { } // order is a,c,b -- 3 comparisons
else { } // order is c,a,b -- 3 comparisons
}
} else {
// partial order = b,a
if (c<b) { } // 2 comparisons: order is c,b,a
else { // order is b,c,a or b,a,c
if (c>a) { } // order is b,a,c -- 3 comparisons
else { } // order is b,c,a -- 3 comparisons
}
}
作为补充说明:某些语言(Fortran,IIRC)以及一些ISA(VAX,再次IIRC)支持比较,其中下一个PC地址从三个选项中选择:LT,EQ,GT。如果字母足够小,这个机会可以略微减少所需的比较次数。
另外,这可能没有实际用途,因为过于复杂的嵌套结构导致的错误分支预测的惩罚可能比保存的比较的收益大得多。
答案 4 :(得分:1)
更像这样
#define MEDIAN(a,b,c) ( (a > b) ? max(b, min(a,c)) :
min(b, max(a,c)) )
答案 5 :(得分:0)
Python V2
def bigger(a,b):
if a > b:
return a
else:
return b
def biggest(a,b,c):
return bigger(a,bigger(b,c))
def median(a,b,c):
big = biggest(a,b,c)
if big == a:
return bigger(b,c)
if big == b:
return bigger(a,c)
else:
return bigger(a,b)
打印中位数
print(median(1,18,10)) # => 10
答案 6 :(得分:0)
仅使用两个比较:
double median_of_three(double left, double middle, double right)
{
double med = middle;
if (left < med) med = left;
if (right > med) med = right;
return med;
}