简体   繁体   English

在C#中递归实现QuickSort

[英]Implementing QuickSort recursively in C#

I started learning algorithms and I am trying to implement Quicksort in C#. 我开始学习算法,并试图在C#中实现Quicksort。 This is my code: 这是我的代码:

class QuickSortDemo
{
    public void Swap(ref int InputA, ref int InputB)
    {
        InputA = InputA + InputB;
        InputB = InputA - InputB;
        InputA = InputA - InputB;
    }

    public int Partition(int[] InputArray, int Low, int High)
    {
        int Pivot = InputArray[Low];
        int LoopVariable1 = Low - 1;
        int LoopVariable2 = High + 1;
        while (true)
        {

            while (InputArray[--LoopVariable2] > Pivot) ;

            while (InputArray[++LoopVariable1] < Pivot) ;


            if (LoopVariable1 < LoopVariable2)
            {
                Swap(ref InputArray[LoopVariable1], ref InputArray[LoopVariable2]);
                for (int LoopVariable = Low; LoopVariable <= High; LoopVariable++)
                {
                    Console.Write(InputArray[LoopVariable] + " ");
                }
                Console.WriteLine();

            }
            else
            {
                for (int LoopVariable = Low; LoopVariable <= High; LoopVariable++)
                {
                    Console.Write(InputArray[LoopVariable] + " ");
                }
                Console.WriteLine();
                return LoopVariable2;
            }
        }
    }

    public void QuickSort(int[] InputArray,int Low, int High)
    {
        if (Low < High)
        {
            int Mid = Partition(InputArray, Low, High);
            QuickSort(InputArray, Low, Mid);
            QuickSort(InputArray, Mid + 1, High);
        }
    }
    public static void Main()
    {
        int[] InputArray = { 10, 5, 6, 8, 23, 19, 12, 17 };
        QuickSortDemo Demo = new QuickSortDemo();
        for (int LoopVariable = 0; LoopVariable < InputArray.Length; LoopVariable++)
        {
            Console.Write(InputArray[LoopVariable]+" ");
        }
        Console.WriteLine();

        Demo.QuickSort(InputArray, 0, InputArray.Length - 1);
        for (int LoopVariable = 0; LoopVariable < InputArray.Length; LoopVariable++)
        {
            Console.Write(InputArray[LoopVariable] + " ");
        }
        Console.WriteLine();
    }
}

For some reason I can't get this to work when I take the rightmost element in the array as pivot. 由于某种原因,当我将数组中最右边的元素作为数据透视时,我无法使它正常工作。 I don't know what I am doing wrong. 我不知道我在做什么错。 It would be really helpful if someone could explain me why this doesn't work when I take my rightmost element as the pivot. 如果有人可以解释一下为什么当我以我最右边的元素为枢轴时这不起作用,那将非常有帮助。 From what I learned, this should work for any input and any pivot element. 据我了解,这应该适用于任何输入和任何枢轴元素。 Correct me if I am wrong. 如果我错了,请纠正我。 Thank you. 谢谢。

I'm still not entirely sure I understand the question. 我仍然不确定我是否理解这个问题。 But I was able to reproduce a problem (infinite recursion) when I change the line of code in the Partition() method from int pivot = inputArray[low]; 但是当我从int pivot = inputArray[low];更改Partition()方法中的代码行时,我能够重现问题(无限递归) int pivot = inputArray[low]; to int pivot = inputArray[high]; int pivot = inputArray[high]; , and doing so seems consistent with your narrative: ,这似乎与您的叙述相符:

I can't get this to work when I take the rightmost element in the array as pivot. 当我将数组中最右边的元素作为数据透视时,我无法使它正常工作。


If I've understood the question correctly, then the basic problem is that when you change where you get the pivot, you also need to take this into account when returning the new mid-point. 如果我已经正确理解了这个问题,那么基本的问题是,当您更改获取轴的位置时,在返回新的中点时也需要考虑到这一点。 Currently, you return loopVariable2 , which is correct when picking the pivot from the lower end of the array. 当前,您返回loopVariable2 ,这是从数组下端拾取枢轴时正确的。 But if you switch to picking the pivot from the upper end of the array, you need to return loopVariable2 - 1 . 但是,如果切换到从数组的上端拾取枢轴,则需要返回loopVariable2 - 1

Another problem is that as you are scanning, you unconditionally increment or decrement the respective "loop variable", regardless of whether the current index is already at an element in the wrong partition. 另一个问题是,在扫描时,无论当前索引是否已位于错误分区中的某个元素上,您都将无条件地递增或递减相应的“循环变量”。 You need to check the current element position first, and only adjust the index if that element is in the correct partition. 您需要首先检查当前元素的位置,并且仅在该元素位于正确分区中时才调整索引。

Here is a correct version of the Partition() method where the pivot is selected using high instead of low : 这是Partition()方法的正确版本,其中使用high而不是low来选择枢轴:

    public int Partition(int[] inputArray, int low, int high)
    {
        int pivot = inputArray[high];
        int loopVariable1 = low;
        int loopVariable2 = high;
        while (true)
        {

            while (inputArray[loopVariable2] > pivot) loopVariable2--;

            while (inputArray[loopVariable1] < pivot) loopVariable1++;


            if (loopVariable1 < loopVariable2)
            {
                Swap(ref inputArray[loopVariable1], ref inputArray[loopVariable2]);
                for (int loopVariable = low; loopVariable <= high; loopVariable++)
                {
                    Console.Write(inputArray[loopVariable] + " ");
                }
                Console.WriteLine();

            }
            else
            {
                for (int loopVariable = low; loopVariable <= high; loopVariable++)
                {
                    Console.Write(inputArray[loopVariable] + " ");
                }
                Console.WriteLine();
                return loopVariable2 - 1;
            }
        }
    }

In either case, note that the effect is to ensure that regardless of the pivot value selected, you always partition the array in such a way to ensure that a new pivot is always selected with each level of recursion, preventing the infinite loop. 在这两种情况下,请注意,其效果是确保不管选择的枢轴值如何,都始终以这种方式对数组进行分区,以确保每次递归级别都始终选择新的枢轴,从而避免了无限循环。


By the way, and for what it's worth, I would not implement Swap() as you have. 顺便说一句,对于它的价值,我不会像您那样实现Swap() It's an interesting gimmick to do a no-temp-variable swap, but there is no practical benefit to doing so, while it does incur a significant code maintenance and comprehension cost. 进行无温度变量交换是一个有趣的interesting头,但是这样做没有任何实际好处,尽管这样做确实会导致大量的代码维护和理解成本。 In addition, it will only work with integral numeric types; 另外,它仅适用于整数数值类型; what if you want to extend your sort implementation to handle other types? 如果您想扩展您的排序实现以处理其他类型怎么办? Eg ones that implement IComparable or where you allow the caller to provide an IComparer implementation? 例如那些实现IComparable或允许调用者提供IComparer实现的地方?

IMHO a better Swap() method looks like this: 恕我直言,更好的Swap()方法如下所示:

    public void Swap<T>(ref T inputA, ref T inputB)
    {
        T temp = inputA;

        inputA = inputB;
        inputB = temp;
    }

quick sort: 快速排序:

   static public int Partition(int [] numbers, int left, int right)
    {
        int pivot = numbers[left];
          while (true)
          {
            while (numbers[left] < pivot)
                left++;

            while (numbers[right] > pivot)
                right--;

            if (left < right)
                {
                int temp = numbers[right];
                numbers[right] = numbers[left];
                numbers[left] = temp;
                }
                else
                {
                      return right;
                }
          }
    }

    static public void QuickSort_Recursive(int [] arr, int left, int right)
    {
        // For Recusrion
        if(left < right)
        {
            int pivot = Partition(arr, left, right);

            if(pivot > 1)
                QuickSort_Recursive(arr, left, pivot - 1);

            if(pivot + 1 < right)
                QuickSort_Recursive(arr, pivot + 1, right);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM