あなたの問題は、<
比較のために依存するようにクイックソートを設計していることです。
<
1/2を2/4未満に再定義することですぐに解決できますが<
、分数として使用された他のすべてのケースが台無しになります。
ソートを通常の.NETの方法で定義する必要があります。ここでは、System.Comparison
デリゲートを受け取るフォーム、System.IComparer
それらを使用しないオーバーロード、およびこれらによって実装されるオーバーロードがあります。
internal class DelegateComparer<T> : IComparer<T>
{
private Comparison _del;
public DelegateComparer(Comparison del)
{
_del = del;
}
public int Compare(T x, T y)
{
return _del(x, y);
}
}
public static void Quicksort(Fraction[] f, int p, int r, IComparer<Fraction> cmp)
{
/* This is the only method with the real implementation */
}
public static void Quicksort(Fraction[] f, int p, int r)
{
QuickSort(f, p, r, Comparer<Fraction>.Default);
}
public static void Quicksort(Fraction[] f, int p, int r, Comparison<Fraction> cmp)
{
QuickSort(f, p, r, new DelegateComparer(cmp));
}
public static void QuickSort(Fraction[] f)
{
QuickSort(f, 0, f.Length, Comparer<Fraction>.Default);
}
これで、2/4の前に1/2を置くという奇妙なケースに対して行う必要があるのは、これを行うカスタム比較ツールだけです。Fraction
クラスが次のようなものであると仮定しましょう。
public class Fraction
{
public int Denominator{get;set;}
public int Numerator{get;set;}
public double Value
{
return (double) Numerator / (double) Denominator;
}
}
次に、トリックを実行するIComparer<Fraction>
またはをすばやく作成できます。Comparison<Fraction>
2番目のオプションを取りましょう:
private static int CompareSepDenom(Fraction x, Fraction y)
{
int cmp = x.Value.CompareTo(y.Value);//normal comparison first
if(cmp == 0)//same value;
return x.Numerator.CompareTo(y.Numerator);//put lower numerator (also lower denum) first
return cmp;
}
これが実験ではなく実際のコードである場合は、クイックソートを実装する必要はありません。とにかくクイックソートArray.Sort
を使用するからです。List<T>.Sort
だから私たちはただすることができます:
Array.Sort(arrayOfFractions, CompareSepDenom);
または、CompareSepDenomを再利用せず、ラムダからの匿名のデリゲートが必要な場合は、次を使用できます。
Array.Sort(arrayOfFractions, (x, y) =>
{
int cmp = x.Value.CompareTo(y.Value);//normal comparison first
if(cmp == 0)//same value;
return x.Numerator.CompareTo(y.Numerator);//put lower numerator (also lower denum) first
return cmp;
});
一方、クイックソートを実験として書いている場合、またはコードから学ぶ場合は、依存しているという事実は、定義さICmparer<Fraction>
れている特定のタイプを受け入れるようにメソッドをコーディングすることに制限されなくなったことを意味することに注意してください<
。
これは、次のようなメソッドを記述できることを意味します。
public static void QuickSort<T>(T[] arr, int p, int r, IComparer<T> cmp)
これはすべてのタイプで機能します。
それが済んだら、ライブラリに組み込まれているバージョンと比較します。
編集:
ちなみに、まだやっていない場合に備えて。Fraction
クラスは、(.NET1.0との下位互換性のために)を実装する必要がIComparable<Fraction>
ありますIComparable
。これにより、独自の比較デリゲートまたはクラスを作成したくない人は、分数(1/2および2/4)の通常の並べ替えを取得できます。同等です)。最初の実装が完了したら:
CompareTo(Fraction other)
{
if(other == null)//take out this of Fraction is a struct
return 1;
return Value.CompareTo(other.Value)
}
CompareTo(object obj)
{
if(other == null)
return 1;
Fraction fract = other as Fract;
if(fract == null)
throw new ArgumentException("Can only compare with other factions", "obj");
return CompareTo(fract);
}
次にこれを使用するためComparer<Fraction>.Default
、他の方法での順序付けに依存する他のコードと同様に、比較子を使用しないバージョンのsortメソッドが機能します。実際、「通常の順序付け方法」が理にかなっているクラス、または、、などを定義するクラスには、<
それら>
が<=
必要です。また、これらの演算子のオーバーロードをすべてルーティングすることもできCompareTo
ます(実際にはインライン化されるため、パフォーマンスの低下はありません`)。つまり、ほぼすべてのクラスで同じコードが機能します。