您的问题是您正在设计快速排序以<
进行比较。
您可以通过将 1/2 重新定义<
为小于 2/4 来立即解决它,但这会弄乱所有其他<
用作分数的情况。
您应该以正常的 .NET 方式定义您的排序,其中您有一个采用System.Comparison
委托的表单,一个采用 a 的表单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);
}
完成后,对于将 1/2 放在 2/4 之前的奇怪情况,您需要做的就是执行此操作的自定义比较器。假设您的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>
来解决问题。让我们采取第二个选项:
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,而是希望有一个来自 lambda 的匿名委托,您可以使用:
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
类应该实现IComparable<Fraction>
and IComparable
(为了与 .NET1.0 向后兼容),以便不想创建自己的比较器委托或类的人可以获得分数的正常排序(其中 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
将反过来使用它,所以不采用比较器的排序方法的版本将起作用,其他依赖于以其他方式排序的代码也将起作用。真的,对于任何“正常的排序方式”有意义的类,或者你定义<
的类,>
等等<=
,都应该有它们。您还可以通过CompareTo
(在实践中最终会被内联,因此没有性能损失`)路由所有这些运算符重载,这意味着相同的代码几乎适用于任何此类。