在c#中实现快速排序有困难

本文关键字:快速排序 实现 | 更新日期: 2023-09-27 18:04:00

我有一点麻烦,试图让这个快速排序算法工作100%。到目前为止,当它试图交换两个相同的数字时,它会有点挂起(试图补救,正如您将在代码中看到的那样)。

那该死的东西就快到了。我只是不确定我错过了什么。我花了几个小时想弄明白,但无济于事。

我正在为课堂做这个,不幸的是我的老师说他不能帮助我,因为我在做泛型(额外的学分),他只能在c#中拉动字符串或整数(他主要是java/c++老师....他使用c#的时间并不长)。

快速排序静态类

class QuickSort<T> where T : IComparable<T>
{
    //No variables or properties, more of a helper class
    //This is the method that will be called by the user.
    //It ties the internal methods into one to sort the
    //array. It needs an array passed into it, As well as
    //the size of the array.
    public static void  QSort(T[] array,int size)
    {
        //If array is empty, or has 1 element, it is sorted.
        //Return immediatly.
        if (size == 1 || size == 0)
        { return; }
        else
        {   
            //Time to sort, pass in the array, the left bounds of 0,
            //and the right bounds of high - 1 (the last element).
            Partition(array, 0, size);
        }
    }
    //This method splits the work area in half, putting lower
    //values left of the pivot, and greater values right of
    //the pivot.
    private static void Partition(T[] array, int lower, int upper)
    {
        //If upper is less 1, then there is no
        //sorting that can be done.
        if ((upper - lower) < 2)
        { return; }
        //Get the right bound -1, to make sure it stays
        //within actual array bounds
        int left = lower;
        int right = upper-1;
        //Set pivot to equal the middle most array. I used this
        //expression because wikipedia mentions it will stop
        //overflow and invalid pivot position that can come
        //with exceptionally large arrays using the basic
        //(a+b)/2 equation.
        int pivot_index = left + (right - left) / 2;
        T pivot = array[pivot_index];
        while (left < right)
        {
            //array[left] < pivot
            while ((array[left].CompareTo(pivot) <= 0) && (left < right))
            {
                left++;
            }
            //array[right] > pivot
            while ((array[right].CompareTo(pivot) >= 0)&& (left < right))
            {
                right--;
            }

            if (left != right)
            {
                Swap(array, left, right);
                left++;
                right--;
            }
        }
            //Send in the lower bound, and the pivot point.
            Partition(array, lower, right);
            //Send in the pivot point as lower bound, and upper
            Partition(array, right+1, upper);
    }

    //This method simply swaps the first position with the second.
    private static void Swap(T[] array, int position1, int position2)
    {
        T tempHolder = array[position1];
        array[position1] = array[position2];
        array[position2] = tempHolder;
    }
}

主类

class Tester
{
    static void Main(string[] args)
    {
        ContiguousList<int> tester = new ContiguousList<int>(100);
        Random rand = new Random(5433);
        for (int ii = 0; ii < tester.Size; ii++)
        {
            tester.SetElement(ii, rand.Next(0, 100));
        }
        for (int ii = 0; ii < tester.Size; ii++)
        {
            Console.WriteLine(tester.GetElement(ii).ToString());
        }
        Console.WriteLine();

        tester.Sort();
        for (int ii = 0; ii < tester.Size; ii++)
        {
            Console.WriteLine(tester.GetElement(ii).ToString());
        }

    }
}

这对我来说相当困难,因为我能遵循的唯一在线实现要么是c++(找到一个很好的伪代码解释,如果我能使用指针>.<),要么是它们仅用于整数排序。

我想也许交换是缺失的,或者我的逻辑处理如果数组[左]==数组[右]是错误的。

(哦,不要介意main中的continuouslist…我们的老师让我们编写了自己的智能数组,并告诉我们使用它,这样我们就可以看到智能数组是如何工作的。

谢谢大家的帮助。我的脑子被这个问题难住了。

——编辑我改变了循环,一个检查>= 0,另一个检查<0去掉不需要的支票

——编辑我又调整了一下,现在它似乎仍然是有序的,但不是完全有序,我的前10个元素是1,1,2,3,2,3,6,5,4,5所以不知怎的,当值相同时,有些东西没有被交换。

编辑—只是重读了一下我使用的快速排序解释/伪代码,并注意到一个小的"这个版本将只适用于具有唯一元素的数组"警告…所以我是对的,因为当2个元素持有相同的值时,它必须这样做,有些东西不起作用……

在c#中实现快速排序有困难

由于第一个循环,左元素不能小于枢轴。右边的元素不能大于主元,因为有第二个循环。所以如果它们相等,那么它们一定都等于主轴,因此它们最终在数组的哪一半都无关紧要。

无论如何,我认为你需要做的就是稍微调整一下这些行:

        if (array[left].CompareTo(array[right]) == 0)
        {
            left++;
            right--;
        }
        else if (left != right)
        {
            Swap(array, left, right);
            left++;
            right--;
        }

但是这里有几个简化:

  1. 因为left == right意味着array[left].CompareTo(array[right]) == 0),你的left != right测试是多余的。
  2. 作为推论,你总是以左递增和右递减结束。所以你可以把它移到条件语句之外。
因此结果代码看起来像这样:
        if (array[left].CompareTo(array[right]) != 0)
        {
            Swap(array, left, right);
        }
        left++;
        right--;

您应该更改swap方法以交换实际数据,而不是访问数组。在c#中,你需要'ref',所以任何数据都会作为引用发送:

    private static void Swap(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }