3つの数値の配列が与えられ、3つの値の中間値を知りたいのですが。
問題は、何ですか 最速 の方法 3つの中間を見つける?
私のアプローチはこの種のパターンです-3つの数字があるので、6つの順列があります:
if (array[randomIndexA] >= array[randomIndexB] &&
array[randomIndexB] >= array[randomIndexC])
誰かが私を見つけるのを手伝うことができれば、それは本当に素晴らしいでしょう よりエレガント そして もっと早く これを行う方法。
あなたが最も効率的なソリューションを探しているなら、私はそれが次のようなものだと思います:
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";
}
}
このアプローチでは、少なくとも2回、最大3回の比較が必要です。 2つの値が等しくなる可能性を意図的に無視します(質問と同様)。これが重要な場合は、アプローチを拡張してこれを確認することもできます。
ここには、min/maxを使用し、ブランチを使用しないという答えがあります( https://stackoverflow.com/a/14676309/22336 )。実際には、中央値を見つけるには4 min/max操作で十分です。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
ハードウェアがブランチなしでminおよびmaxクエリに回答できる場合、ブランチなしでクエリに回答することが可能です(今日のほとんどの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関数を選択する必要があります。正のフロートのみが存在する場合、浮動小数点表現で整数min/maxを直接使用することができます(整数演算は一般に高速であるため、これが望ましい場合があります)。
ハードウェアがmin/maxをサポートしないというまれなシナリオでは、次のようなことができます。
max(a,b)=(a+b+|a-b|)/2
min(a,b)=(a+b-|a-b|)/2
ただし、float操作を使用する場合、正確なmin/maxが必要であり、それに近いものではないため、これは正しくありません。幸いなことに、float min/maxは古くからハードウェアでサポートされています(x86、Pentium III以降)。
これは、最大で2つの比較で実行できます。
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;
}
そしてもう1つのアイデア。 3つの数字があります{a,b,c}
。次に:
middle = (a + b + c) - min(a,b,c) - max(a,b,c);
もちろん、数値の制限については覚えておく必要があります...
条件のみを使用してこれを表現する方法は次のとおりです。
int a, b, c = ...
int middle = (a <= b)
? ((b <= c) ? b : ((a < c) ? c : a))
: ((a <= c) ? a : ((b < c) ? c : b));
編集:
スワップを実装するソリューションが見つかりませんでした:
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;
}
これを最も簡単な方法で書くこともできます。あなたが言ったように、たった6つの可能性があります。より高速または低速になる合理的なアプローチはないので、読みやすいものを探してください。
簡潔にするためにmin()とmax()を使用しますが、3つのネストされたif/thenも同じように良いと思います。
いくつかの基準を満たすX値の1つを見つける必要がある場合、少なくともその値を他のX-1のそれぞれと比較する必要があります。 3つの値の場合、これは少なくとも2つの比較を意味します。これは「最小でも最大でもない値を見つける」ことなので、2つの比較だけで済みます。
次に、コードの記述に集中して、何が起こっているかを非常に明確に確認し、シンプルに保つ必要があります。ここで、これはネストされたifを意味します。これにより、JVMは実行時にこの比較を可能な限り最適化できます。
この例を参照するには、Timが提供するソリューション( トリプルの中間値を見つける最も速い方法? )を参照してください。多くのコード行は、ネストされた疑問符のコロンよりも大きなコードであるとは限りません。
median = (a+b+c) - Math.min(Math.min(a,b),c) - Math.max(Math.max(a,b),c)
これは基本的なものです。これがどれほど効率的かはわかりませんが、これらの関数はif条件を使用します。必要に応じて、このステートメントをif-elseステートメントに変換できますが、時間がかかります。なぜそんなに怠zyなのか?
最も簡単な方法は並べ替えです。たとえば、次のコードを検討してください。
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の異なる値がある場合は、このコードを使用して中央の値を見つけることもできます。
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)
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は、これらの3項割り当てごとにConditionalNodeを生成し、cmp/cmov
アセンブリ内のペア。また、比較は、等しい場合にアルファベット順の最初のインデックスが返されるように選択されていることに注意してください。
方法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");
}
}
トリプルの中間値を見つける の適切なansを得ました
古いスレッドを増やしたが、それでも最短の解決策であり、誰もそれについて言及しなかった。
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
の場合はfalse-a
を返します。
それ以外の場合は、(a > b) ^ (b > c)
またはa > b > c
の場合はa < b < c
false-bを返します。
それ以外の場合は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;
}
入力の一部が等しい場合でも、ソリューションは正常に機能します。これは明らかではないかもしれませんが、かなり論理的です。
これは動作します:
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);
}
}
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;
}
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;
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は全体の最小値であり、他の値は中間値でなければなりません。等価性をチェックするため、配列値を比較する代わりに、最後の行のインデックスを比較できます。
整数の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)); }
きれいに見えないかもしれませんが、一部のアーキテクチャではマシンコードがより効率的であることが判明する場合があります。特に、最小/最大の指示がないもの。しかし、私はそれを確認するベンチマークを作成していません。
次のように配列を使用できます。
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);
}