给定是一个包含三个数值的数组,我想知道这三个数值的中间值。
问题是,找到三个中间的最快方式是什么?
我的方法是这种模式 - 因为有三个数字有六种排列:
if (array[randomIndexA] >= array[randomIndexB] &&
array[randomIndexB] >= array[randomIndexC])
如果有人可以帮我找到更优雅的和更快的方式,那将是非常好的。
答案 0 :(得分:76)
这里有一个答案,使用min / max和no branches(https://stackoverflow.com/a/14676309/2233603)。实际上4分钟/最大值操作足以找到中位数,不需要xor:
median = max(min(a,b), min(max(a,b),c));
虽然,它不会给你中值的索引...
所有案件的细分:
a b c
1 2 3 max(min(1,2), min(max(1,2),3)) = max(1, min(2,3)) = max(1, 2) = 2
1 3 2 max(min(1,3), min(max(1,3),2)) = max(1, min(3,2)) = max(1, 2) = 2
2 1 3 max(min(2,1), min(max(2,1),3)) = max(1, min(2,3)) = max(1, 2) = 2
2 3 1 max(min(2,3), min(max(2,3),1)) = max(2, min(3,1)) = max(2, 1) = 2
3 1 2 max(min(3,1), min(max(3,1),2)) = max(1, min(3,2)) = max(1, 2) = 2
3 2 1 max(min(3,2), min(max(3,2),1)) = max(2, min(3,1)) = max(2, 1) = 2
答案 1 :(得分:35)
如果硬件可以回答没有分支的最小和最大查询(今天大多数CPU可以执行此操作),则可以在没有分支的情况下回答查询。
运算符^表示按位xor。
Input: triple (a,b,c)
1. mx=max(max(a,b),c)
2. mn=min(min(a,b),c)
3. md=a^b^c^mx^mn
4. return md
这是正确的,因为:
应为int / float选择适当的最小/最大函数。 如果只存在正浮点数,那么可以直接在浮点表示上使用整数最小值/最大值(这可能是合乎需要的,因为整数运算通常更快)。
在硬件不支持min / max的不太可能的情况下,可以这样做:
max(a,b)=(a+b+|a-b|)/2
min(a,b)=(a+b-|a-b|)/2
但是,使用浮点运算时这是不正确的,因为需要精确的最小值/最大值而不是接近它的值。幸运的是,浮动最小/最大值已经硬件支持多年(在x86上,从奔腾III及以后)。
答案 2 :(得分:25)
如果您正在寻找最有效的解决方案,我会想象它是这样的:
if (array[randomIndexA] > array[randomIndexB]) {
if (array[randomIndexB] > array[randomIndexC]) {
return "b is the middle value";
} else if (array[randomIndexA] > array[randomIndexC]) {
return "c is the middle value";
} else {
return "a is the middle value";
}
} else {
if (array[randomIndexA] > array[randomIndexC]) {
return "a is the middle value";
} else if (array[randomIndexB] > array[randomIndexC]) {
return "c is the middle value";
} else {
return "b is the middle value";
}
}
这种方法需要至少两次,最多三次比较。它故意忽略了两个值相等的可能性(就像你的问题一样):如果这很重要,可以扩展方法来检查这个。
答案 3 :(得分:20)
这可以通过最多两次比较来完成。
int median(int a, int b, int c) {
if ( (a - b) * (c - a) >= 0 ) // a >= b and a <= c OR a <= b and a >= c
return a;
else if ( (b - a) * (c - b) >= 0 ) // b >= a and b <= c OR b <= a and b >= c
return b;
else
return c;
}
答案 4 :(得分:12)
还有一个想法。有三个数字{a,b,c}
。然后:
middle = (a + b + c) - min(a,b,c) - max(a,b,c);
当然,我们必须记住数字限制......
答案 5 :(得分:7)
以下是仅使用条件表达的方法:
int a, b, c = ...
int middle = (a <= b)
? ((b <= c) ? b : ((a < c) ? c : a))
: ((a <= c) ? a : ((b < c) ? c : b));
编辑:
答案 6 :(得分:4)
我没有看到实施互换的解决方案:
int middle(int a, int b, int c) {
// effectively sort the values a, b & c
// putting smallest in a, median in b, largest in c
int t;
if (a > b) {
// swap a & b
t = a;
a = b;
b = t;
}
if (b > c) {
// swap b & c
t = b;
b = c;
c = t;
if (a > b) {
// swap a & b
t = a;
a = b;
b = t;
}
}
// b always contains the median value
return b;
}
答案 7 :(得分:3)
你也可以用最简单的方式写这个。正如你所说,只有六种可能性。没有合理的方法可以更快或更慢,所以只需要一些易于阅读的东西。
我会使用min()和max()来表示简洁,但是我认为三个嵌套if / thens会一样好。
答案 8 :(得分:2)
如果必须找到满足某些标准的X值中的一个,则必须至少将该值与每个X-1其他值进行比较。对于三个值,这意味着至少两次比较。既然这是“找到不是最小而不是最大的价值”,那么你只需要进行两次比较即可获得。
然后你应该专注于编写代码,这样你就可以非常清楚地看到发生了什么并保持简单。这意味着嵌套if。这将允许JVM在运行时尽可能地优化此比较。
请参阅Tim(Fastest way of finding the middle value of a triple?)提供的解决方案,以查看此示例。许多代码行不一定比嵌套的questionmark-colon更大。
答案 9 :(得分:2)
median = (a+b+c) - Math.min(Math.min(a,b),c) - Math.max(Math.max(a,b),c)
这是最基本的,我不知道这会有多高效,但这些功能毕竟是条件。如果您愿意,可以将此语句转换为if-else语句,但这需要时间。为什么这么懒?
答案 10 :(得分:2)
最简单的方法是通过排序。 例如,请考虑以下代码:
import java.util.Arrays;
int[] x = {3,9,2};
Arrays.sort(x); //this will sort the array in ascending order
//so now array x will be x = {2,3,9};
//now our middle value is in the middle of the array.just get the value of index 1
//Which is the middle index of the array.
int middleValue = x[x.length/2]; // 3/2 = will be 1
就是这样。这很简单。
通过这种方式,您无需考虑数组的大小。如果您有47个不同的值,那么您也可以使用此代码来查找中间值。
答案 11 :(得分:1)
这个会起作用:
template<typename T> T median3_1_gt_2(const T& t1, const T& t2, const T& t3) {
if (t3>t1) {
return t1;
} else {
return std::max(t2, t3);
}
}
template<typename T> T median3(const T& t1, const T& t2, const T& t3) {
if (t1>t2) {
return median3_1_gt_2(t1, t2, t3);
} else {
return median3_1_gt_2(t2, t1, t3);
}
}
答案 12 :(得分:1)
if(array[aIndex] > array[bIndex]) {
if(array[bIndex] > array[cIndex]) return bIndex;
if(array[aIndex] > array[cIndex]) return cIndex;
return aIndex;
} else {
if(array[bIndex] < array[cIndex]) return bIndex;
if(array[aIndex] < array[cIndex]) return cIndex;
return aIndex;
}
答案 13 :(得分:1)
// Compute median of three values, no branches
int median3(int V[3])
{
unsigned int A,B,C;
A=(V[0] < V[1]);
B=(V[1] < V[2]);
C=(V[0] < V[2]);
return V[(B^C)<<1 | (A^B^1)];
}
答案 14 :(得分:1)
打破旧线程,但它仍然是最短的解决方案,没有人提及它。
int median2(int a, int b, int c) {
return (a > b) ^ (a > c) ? a : (a > b) ^ (b > c) ? c : b;
}
(测试涵盖所有可能的组合,所有组合打印6)
public static void main(String[] args) {
System.out.println(median(3, 6, 9));
System.out.println(median(3, 9, 6));
System.out.println(median(6, 3, 9));
System.out.println(median(6, 9, 3));
System.out.println(median(9, 3, 6));
System.out.println(median(9, 6, 3));
System.out.println(median(6, 6, 3));
System.out.println(median(6, 6, 9));
System.out.println(median(6, 3, 6));
System.out.println(median(6, 9, 6));
System.out.println(median(3, 6, 6));
System.out.println(median(9, 6, 6));
System.out.println(median(6, 6, 6));
}
(a > b) ^ (a > c)
或c > a > b
- 返回c < a < b
,则 a
为false;
(a > b) ^ (b > c)
或a > b > c
- 返回b; ,则否则a < b < c
为false
否则返回c;
让我们假设p = a > b
; q = b > c
; s = a > c
;
让我们构建一个Karnaugh map。
| 00 01 11 10 (p, q)
---+----------------------
0 | b c * a
1 | * a b c
(s)|
*
表示组合是不可能的(例如a > b; b > c; a < c
)
请注意,右侧部分是镜像左侧部分,可以通过引入t = p ^ q; u = s ^ p
来简化地图
| 0 1 (t)
---+---------
0 | b c
1 | * a
(u)|
因此该函数可以写成
private static int median(int a, int b, int c) {
boolean t = (a > b) ^ (b > c);
boolean u = (a > b) ^ (a > c);
if (u)
return a;
else if (t)
return c;
else
return b;
}
用?:内联变量和替换ifs给出答案
int median2(int a, int b, int c) {
return (a > b) ^ (a > c) ? a : (a > b) ^ (b > c) ? c : b;
}
即使输入中的某些内容相等,解决方案也能正常工作,这可能不明显,但非常符合逻辑。
答案 15 :(得分:1)
根据Gyorgy的优秀答案,你可以通过用条件移动替换min / max来得到没有分支的中位数索引:
int i = (array[A] >= array[B]) ? A : B;
int j = (array[A] <= array[B]) ? A : B;
int k = (array[i] <= array[C]) ? i : C;
int median_idx = (array[j] >= array[k]) ? j : k;
javac应为每个三元分配生成一个ConditionalNode,它在汇编中转换为cmp/cmov
对。另请注意,选择的比较使得在相等的情况下,返回按字母顺序排列的第一个索引。
答案 16 :(得分:1)
largest=(a>b)&&(a>c)?a:(b>c?b:c);
smallest=(a<b)&&(a<c)?a:(b<c?b:c);
median=a+b+c-largest-smallest;
答案 17 :(得分:1)
方法1
int a,b,c,result;
printf("enter three number");
scanf("%d%d%d",&a,&b,&c);
result=a>b?(c>a?a:(b>c?b:c)):(c>b?b:(a>c?a:c));
printf("middle %d",result);
方法2
int a=10,b=11,c=12;
//Checking for a is middle number or not
if( b>a && a>c || c>a && a>b )
{
printf("a is middle number");
}
//Checking for b is middle number or not
if( a>b && b>c || c>b && b>a )
{
printf("b is middle number");
}
//Checking for c is middle number or not
if( a>c && c>b || b>c && c>a )
{
printf("c is middle number");
}
方法3
if(a>b)
{
if(b>c)
{
printf("b is middle one");
}
else if(c>a)
{
printf("a is middle one");
}
else
{
printf("c is middle one");
}
}
else
{
if(b<c)
{
printf("b is middle one");
}
else if(c<a)
{
printf("a is middle one");
}
else
{
printf("c is middle one");
}
}
答案 18 :(得分:1)
以下是Python的答案,但同样的逻辑适用于Java程序。
def middleOfThree(a,b,c):
middle = a
if (a < b and b < c) or (c < b and b < a):
middle = b
elif (a < c and c < b) or (b < c and c < a):
middle = c
print 'Middle of a=%d, b=%d, c=%d is %d' % (a,b,c,middle)
middleOfThree(1,2,3)
middleOfThree(1,3,2)
middleOfThree(2,1,3)
middleOfThree(2,3,1)
middleOfThree(3,2,1)
middleOfThree(3,1,2)
答案 19 :(得分:0)
在ary中使用idxA到idxC,
int ab = ary[idxA] < ary[idxB] ? idxA : idxB;
int bc = ary[idxB] < ary[idxC] ? idxB : idxC;
int ac = ary[idxA] < ary[idxC] ? idxA : idxC;
int idxMid = ab == bc ? ac : ab == ac ? bc : ab;
indexMiddle指向中间值。
说明:从3最小值2是总体最小值,另一个值必须是中间值。因为我们检查相等性,我们可以比较最后一行中的索引,而不是必须比较数组值。
答案 20 :(得分:0)
整数的100%无分支版本:
int mid(const int a, const int b, const int c) {
const int d0 = b - a;
const int m = (d0 >> 31);
const int min_ab = a + (d0 & m);
const int max_ab = a + (d0 & ~m);
const int d1 = c - max_ab;
const int min_max_ab_c = max_ab + (d1 & (d1 >> 31));
const int d2 = min_ab - min_max_ab_c;
return min_ab - (d2 & (d2 >> 31));
}
使用无分支的最小/最大函数构建:
int min(const int a, const int b) { const int d = b - a; return a + (d & (d >> 31)); }
int max(const int a, const int b) { const int d = a - b; return a - (d & (d >> 31)); }
它可能看起来不漂亮,但机器代码在某些架构上可能会更有效。特别是没有最小/最大指令的人。但我没有做任何基准来证实它。
答案 21 :(得分:0)
您可以使用数组,如下所示:
private static long median(Integer i1, Integer i2, Integer i3) {
List<Integer> list = Arrays.asList(
i1 == null ? 0 : i1,
i2 == null ? 0 : i2,
i3 == null ? 0 : i3);
Collections.sort(list);
return list.get(1);
}
答案 22 :(得分:-1)
其中很多似乎都在使用非常复杂的if语句。 我使用数学库找到了一个非常简单的解决方法。
Math.max(Math.min(array[start], array[mid]), Math.min(array[start], array[mid], array[end]))
非常好用。
答案 23 :(得分:-1)
或用于在包含中间值的数组中查找索引的单行程序:
int middleIndex = (a[0]<a[1]) ? ((a[0]<a[2) ? a[2] : a[0]) : ((a[1]<a[2) ? a[2] : a[1]);
答案 24 :(得分:-1)
可以由三元运算符在一行中解决
int middle(int A, int B, int C) {
return (A>B&&A>C)?B>C?B:C:(B>C&&B>A)?A>C?A:C:B;
}