注:これを「宿題の質問」と解釈しないでください。これは私が知りたいことです:)
中央値5は、アルゴリズム設計の演習として使用されることがあり、計算可能であることが知られています6つの比較のみを使用。
これを実装するための最良の方法は何ですか"6つの比較を使用した5つの中央値" C#で?私のすべての試みは厄介なコードをもたらすようです:(私はまだ6つの比較だけを使用しながら、素敵で読みやすいコードが必要です。
public double medianOfFive(double a, double b, double c, double d, double e){
//
// return median
//
return c;
}
注:ここでも「アルゴリズム」を提供する必要があると思います:
Azerealが彼のフォーラム投稿で行ったように、アルゴリズムを明確に説明できないことに気づきました。そこで、ここで彼の投稿を参照します。から http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=riddles_cs;action=display;num=1061827085
さて、私は自分の課題の1つでこの問題を提起され、このフォーラムに助けを求めましたが、ここには助けがありませんでした。私は最終的にそれを行う方法を見つけました。
最初の4つの要素でマージソートを開始し、各ペアを並べ替えます(2つの比較)
各ペアの下の2つを比較し、可能性から最も低いものを除外します(3つの比較)
ペアのない数に取っておいた5番目の数を追加し、2つを比較します(4つの比較)
2つの新しいペアのうち最も低い2つのペアを比較し、下のペアを削除します(5つの比較)
1つだけを比較し、最後のペアの小さい方を比較します。小さい方の数値が中央値です。
可能な中央値は括弧内にあります
(54321)
5:4 3:22比較
(4 <5 2 <3 1)
4:23比較
2(4<5 3 1)
1:34比較
2(4<5 1<3)
4:15の比較
1,2(4 <5 3)
4:36比較
1,2(3)4,5
3つは中央値です
編集:あなたの要求として、そして私自身がより多くの反対票を得るのを防ぐために、これは私が中央値5を見つけるために書いたC++コードです。それが厄介であることを気にしないでください:
double StageGenerator::MedianOfFive(double n1, double n2, double n3, double n4, double n5){
double *a = &n1, *b = &n2, *c = &n3, *d = &n4, *e = &n5;
double *tmp;
// makes a < b and b < d
if(*b < *a){
tmp = a; a = b; b = tmp;
}
if(*d < *c){
tmp = c; c = d; d = tmp;
}
// eleminate the lowest
if(*c < *a){
tmp = b; b = d; d = tmp;
c = a;
}
// gets e in
a = e;
// makes a < b and b < d
if(*b < *a){
tmp = a; a = b; b = tmp;
}
// eliminate another lowest
// remaing: a,b,d
if(*a < *c){
tmp = b; b = d; d = tmp;
a = c;
}
if(*d < *a)
return *d;
else
return *a;
}
もっとコンパクトなはずですね。
編集:
@pablitoが彼の答えで指摘したように。組み込みのList.Sort()は、最大13の比較を使用するため、この要件を満たすことができません:]
これは基本的に、C++の例からコードのスワッピングとソートを除外しているだけです。
private static void Swap(ref double a, ref double b) {
double t = a;
a = b;
b = t;
}
private static void Sort(ref double a, ref double b) {
if (a > b) {
double t = a;
a = b;
b = t;
}
}
private static double MedianOfFive(double a, double b, double c, double d, double e){
// makes a < b and c < d
Sort(ref a, ref b);
Sort(ref c, ref d);
// eleminate the lowest
if (c < a) {
Swap(ref b, ref d);
c = a;
}
// gets e in
a = e;
// makes a < b
Sort(ref a, ref b);
// eliminate another lowest
// remaing: a,b,d
if (a < c) {
Swap(ref b, ref d);
a = c;
}
return Math.Min(d, a);
}
この投稿は興味深いものでした。演習として、6つの比較のみを行い、他には何も行わないこれを作成しました。
static double MedianOfFive(double a, double b, double c, double d, double e)
{
return b < a ? d < c ? b < d ? a < e ? a < d ? e < d ? e : d
: c < a ? c : a
: e < d ? a < d ? a : d
: c < e ? c : e
: c < e ? b < c ? a < c ? a : c
: e < b ? e : b
: b < e ? a < e ? a : e
: c < b ? c : b
: b < c ? a < e ? a < c ? e < c ? e : c
: d < a ? d : a
: e < c ? a < c ? a : c
: d < e ? d : e
: d < e ? b < d ? a < d ? a : d
: e < b ? e : b
: b < e ? a < e ? a : e
: d < b ? d : b
: d < c ? a < d ? b < e ? b < d ? e < d ? e : d
: c < b ? c : b
: e < d ? b < d ? b : d
: c < e ? c : e
: c < e ? a < c ? b < c ? b : c
: e < a ? e : a
: a < e ? b < e ? b : e
: c < a ? c : a
: a < c ? b < e ? b < c ? e < c ? e : c
: d < b ? d : b
: e < c ? b < c ? b : c
: d < e ? d : e
: d < e ? a < d ? b < d ? b : d
: e < a ? e : a
: a < e ? b < e ? b : e
: d < a ? d : a;
}
ありがとう。あなたの投稿はかなり古いと思いますが、私の問題には役立ちました。
5つのSSE/AVXレジスタの中央値を計算する方法が必要でした(一度に4つのfloat/8つのfloat、または一度に2つのdouble/4つのdouble):
条件付きジャンプなし
最小/最大命令のみ
最小/最大関数が条件付きジャンプのあるスカラーレジスタ用にプログラムされている場合、私のコードは比較の観点から最適ではありません。しかし、最小/最大関数が対応するCPU命令でコーディングされている場合、実行時にCPUによって条件付きジャンプが実行されないため、私のコードは非常に効果的です。
template<class V>
inline V median(const V &a, const V &b, const V &c)
{
return max(min(a,b),min(c,max(a,b)));
}
template<class V>
inline V median(const V &a, const V &b, const V &c, const V &d, const V &e)
{
V f=max(min(a,b),min(c,d)); // discards lowest from first 4
V g=min(max(a,b),max(c,d)); // discards biggest from first 4
return median(e,f,g);
}
ここで興味深いスレッド:
スレッドからの引用:
数字を配列に入れます。
3つの比較を使用し、a [1] <a [2]、a [4] <a [5]、およびa [1] <a [4]になるように数値をシャッフルします。
A [3]> a [2]の場合、問題はかなり簡単です。 a [2] <a [4]の場合、中央値はa [3]とa [4]の小さい方です。そうでない場合、中央値はa [2]とa [5]の小さい方です。
したがって、a [3] <a [2]です。 a [3]> a [4]の場合、解はa [3]とa [5]の小さい方になります。それ以外の場合、解はa [2]とa [4]の小さい方になります。
これはかなり醜く、リファクタリングを使用する可能性がありますが、すべての比較とスワップを明示的にウォークスルーするため、何が起こっているかを確認できます。
public double medianOfFive(double a, double b, double c, double d, double e){
double median;
// sort a and b
if(a > b) // comparison # 1
{
double temp = a;
a = b;
b = temp;
}
// sort c and d
if(c > d) // comparison # 2
{
double temp = c;
c = d;
d = temp;
}
// replace the lower of a and c with e
// because the lowest of the first four cannot be the median
if(a < c) // comparison # 3
{
a = e;
// re-sort a and b
if(a > b) // comparison # 4
{
double temp = a;
a = b;
b = temp;
}
}
else
{
c = e;
// re-sort c and d
if(c > d) // comparison # 4
{
double temp = c;
c = d;
d = temp;
}
}
// eliminate a or c, because the lowest
// of the remaining four can't be the median either
if(a < c) // comparison #5
{
if(b < c) // comparison #6
{
median = c;
}
else
{
median = b;
}
}
else
{
if(d < a) // comparison #6
{
median = a;
}
else
{
median = d;
}
}
return median;
}
比較の数を確認するだけです。
class MyComparable : IComparable
{
public static int NumberOfComparisons = 0;
public int NumPart { get; set; }
#region IComparable Members
public int CompareTo(object obj)
{
NumberOfComparisons++; //I know, not thread safe but just for the sample
MyComparable mc = obj as MyComparable;
if (mc == null)
return -1;
else
return NumPart.CompareTo(mc.NumPart);
}
#endregion
}
class Program
{
static void Main(string[] args)
{
List<MyComparable> list = new List<MyComparable>();
list.Add(new MyComparable() { NumPart = 5 });
list.Add(new MyComparable() { NumPart = 4 });
list.Add(new MyComparable() { NumPart = 3 });
list.Add(new MyComparable() { NumPart = 2 });
list.Add(new MyComparable() { NumPart = 1 });
list.Sort();
Console.WriteLine(MyComparable.NumberOfComparisons);
}
}
結果は13です。
完全を期すために、質問は ソーティングネットワーク の特定のケースです。これは Knuth(Art of Computer Programming 、vol 3) 詳細に説明しています。 K.E。Batcherによる古典的な論文 この主題については簡潔で読む価値があります。
これはそれを行う必要があります
private Double medianofFive(double[] input)
{
Double temp;
if (input[0] > input[1])//#1 - sort First and Second
{
temp = input[0];
input[0] = input[1];
input[1] = temp;
}
if (input[2] > input[3])//#2 sort Third and Fourth
{
temp = input[2];
input[2] = input[3];
input[3] = temp;
}
// replace the smaller of first and third with 5th, then sort
int smallerIndex = input[0] < input[2] ? 0 : 2;//#3
input[smallerIndex] = input[4];
//sort the new pair
if(input[smallerIndex]>input[smallerIndex+1])//#4
{
temp = input[smallerIndex];
input[smallerIndex] = input[smallerIndex+1];
input[smallerIndex+1] = temp;
}
//compare the two smaller numbers
// then compare the smaller of the two's partner with larger of the two
// the smaller of THOSE two is the median
if (input[2] > input[0])
//#5
{
temp = input[2] > input[1] ? input[1] : input[2];//#6
}
else
{
temp = input[0] > input[3] ? input[3] : input[0];//#6
}
return temp;
}