为什么在QuickSort实现中将枢轴设置为最右边的元素不起作用?

时间:2017-09-06 00:18:17

标签: c# algorithm quicksort

我目前的QuickSort实现,将数据透视表设置为数组中的最后一个元素,导致堆栈溢出异常。将它设置为中间元素,或最左边,工作正常但不正确。我真的想了解原因。

我目前正在学习数据结构和算法,并且我真的想要了解算法工作方式的复杂性。我已经尝试逐步解决以下问题,但递归正在扼杀我。

基本上我将我的枢轴设置为数组中的最后一个元素,并找到小于枢轴的所有元素,并向左增加成为墙。所有更大的元素都交换到右边。

这是我的解决方案

 public static void QuickSort_Recursive(int[] array, int left, int right)
    {

        // only proceed if left is less than right
        if(left < right)
        {
            // get index for left and right barrier
            int pivotIndex = Partition(array, left, right);

            // sort left
            QuickSort_Recursive(array, left, pivotIndex - 1);

            // sort right
            QuickSort_Recursive(array, pivotIndex, right);
        }
    }

    public static int Partition(int[] array, int left, int right)
    {
        // get pivot as last element            
       int pivot = array[right];

        // continue until left passes right
        while (left <= right)
        {
            // continue with left side until you find an element greater than pivot
            while(array[left] < pivot)
            {
                left++;
            }

            // Continue with right until you find an element less than the pivot
            while(array[right] > pivot)
            {
                right--;
            }

            // Only swap if left is less than right
            if(left <= right)
            {
                // swap left and right
                Swap(array, left, right);

                // Increment left and decrement right
                left++;
                right--;
            }

        }

        return left;
    }

任何人都可以帮助我理解为什么将它设置为最正确的元素会导致堆栈溢出异常吗?

编辑:下面是一个与最合适的枢轴一起工作的实现,但是它们的关键是1)它在交换时不包括交换枢轴2)只移动左指针,以便跟踪低位和高位之间的障碍位置3)不移动两个指针

        // Make starting pivot the last one for now
        int pivot = array[right];
        int leftWall = left;

        // Go through array until index before pivot is reached
        for (int i = left; i < right; i++)
        {
            // If item at array[i] is less than or equal to pivot then switch with leftwall
            if(array[i] <= pivot)
            {
                // Swap positions with leftWall
                Swap_Memory(array, i, leftWall);

                // Increment leftwall position
                leftWall += 1;
            }
        }

        // Swap pivot with whatever value is the top lowest number (pivot is 'right' in this case)
        Swap_Memory(array, leftWall, right);

        // return leftwall as pivot
        // Leftwall is barrier between values lower than pivot and those higher
        return leftWall;

1 个答案:

答案 0 :(得分:0)

问题在于您的分区实施。 您必须以这样的方式进行分区,即pivot的索引左侧的所有元素都应小于pivot元素。 以下两件事必须在代码中解决:

  • 所有比较都应基于数据透视而不是索引。
  • 此外,返回值应该是所选枢轴元素的索引。

标准快速分区分区如下所示:

    public static void QuickSort_Recursive(int[] array, int left, int right)
    {

        // only proceed if left is less than right
        if(left < right)
        {
            // get index for left and right barrier
            int pivotIndex = Partition(array, left, right);

            // sort left
            QuickSort_Recursive(array, left, pivotIndex-1);

            // sort right
            QuickSort_Recursive(array, pivotIndex+1, right);
        }
    }

    public static int Partition(int[] array, int left, int right)
    {
      // get pivot as last element            
      int pivot = array[right];

      int i = left - 1;

      for (int j = left; j <= right - 1; j++) {
        if (array[j] <= pivot) {
            i++;
            // Make sure all the elements left of pivot index is less
            swap(array[i], array[j]);
        }
      }

      //Move the pivot to the selected index and return its index
      swap(array[i+1], pivot);

      return i + 1;

    }

希望它有所帮助!