使用快速排序对分数进行排序,并在1/2和2/4之间指定

时间:2012-08-12 15:45:31

标签: c# quicksort fractions

我正在尝试设置快速排序,我希望它对一系列分数进行排序 目前,它不会正确地对具有相等值(例如1/2和2/4)的分数进行分类 1/2需要在2/4之前,但它最终完全随机。

我正在使用的代码是:

   public static void quicksort(Fraction[] f, int p, int r)
    {
        if (p < r)
        {
            int q = partition(f, p, r);
            quicksort(f, p, q - 1);
            quicksort(f, q + 1, r);
        }
    }

    public static int partition(Fraction[] f, int p, int r)
    {
        Fraction pivot = f[r];
        int i = p - 1;
        for (int j = p; j < r; j++)
        {
            if (f[j].Value < pivot.Value)
            {
                i++;
                Fraction wissel = f[i];
                f[i] = f[j];
                f[j] = wissel;
            }
            else
                if (f[j].Value < pivot.Value && f[j].Teller < pivot.Teller)
                {
                    i++;
                    Fraction wissel = f[i];
                    f[i] = f[j];
                    f[j] = wissel;
                }
        }
        Fraction wisselt = f[i + 1];
        f[i + 1] = f[r];
        f[r] = wisselt;
        return i + 1;

    }

有人能说清楚如何做到这一点吗?

编辑:David Archer的建议修正了,谢谢你们。

4 个答案:

答案 0 :(得分:1)

为什么不使用List<T>.Sort()?它是Quick Sort的一个实现。如果您有IComparable<Fraction>实施,那么您只需拨打Sort()即可。如果您想传递特定方法,也可以使用带代表的覆盖。

e.g。如果你的Fraction课程是这样的:

    public class Fraction : IComparable<Fraction>
    {
     public int CompareTo(Fraction other)
     {
       // if other equals this, return 0
       // if other is greater than this, return -1
       // if other is less than this, return 1
     }
//...
    }

然后你可以只有一个List变量并调用它的Sort方法:

myList.Sort();

答案 1 :(得分:1)

我认为你想要的比较是这样的:

static int CompareFractions(Fraction a, Fraction b)
{
    // compare the value of the fractions
    int c = (a.numerator * b.denominator).CompareTo(a.denominator * b.numerator);
    if (c == 0)
        // break ties with "lowest numerator first"
        c = a.numerator.CompareTo(b.numerator);
    return c;
}

您也可以将其用作普通Sort方法的排序委托。

答案 2 :(得分:1)

您的问题是您正在设计快速排序以依赖<进行比较。

您可以通过重新定义<以使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>来完成这个伎俩。让我们采取第二种选择:

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.SortList<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>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将依次使用它,所以不采用比较器的sort方法的版本将起作用,其他代码依赖于以其他方式排序。实际上,对于任何“正常排序方式”有意义的课程,或者您定义<><=等的课程,都应该有。您还可以通过CompareTo路由所有这些运算符重载(它最终会在实践中被内联,所以没有性能损失),这意味着相同的代码适用于任何此类类。

答案 3 :(得分:0)

我不确定您正在使用的Fraction类,但如果您需要区分1/2和2/4(严格的数学术语相同),我建议您创建自己的比较方法并使用它们而不是内置的大于和小于运算符。

bool IsLessThan(Fraction a, Fraction b)
{
    // Your code here that results in 1/2 being less than 2/4
}

bool IsGreaterThan(Fraction a, Fraction b)
{
    // Your code here that results in 2/4 being greater than 1/2
}