快速排序分区算法

6
我正在尝试编写Cormen算法教材中的快速排序算法。以下是我的代码。
class Quicksort
{
    public void qSort(int[] a, int p, int r)
    {
        if(p<r)
        {
            int q = Partition(a, p,r);
            qSort(a, p, q-1);
            qSort(a, q+1, r);
        }
     }

     private int Partition(int[] a, int p, int r)
     {
         int x = a[r];

         int i = p-1;
         int temp=0;

         for(int j=p; j<r-1; j++)
         {
             if(a[j]<=x)
             {
                 i++;
                 temp = a[i];
                 a[i] = a[j];
                 a[j] = temp;
             }
         }

         temp = a[i+1];
         a[i+1] = a[r];
         a[r] = temp;
         return (i+1);
     }
}

public class QuickSortTest
{
     public static void main(String[] args)
     {
         Quicksort qsort = new Quicksort();
         int[] array = {5, 4, 7, 2, 1, 9, 3, 6, 10, 8};

         System.out.print("Original  Array : ");
         for(int i=0; i<array.length;i++)
         {
             System.out.print(array[i] + " ");
         }

         int length = array.length;

         qsort.qSort(array, 0, length-1);

         System.out.print("Sorted  Array : ");
         for(int i=0; i<array.length;i++)
         {
             System.out.print(array[i] + " ");
         }
     }
}

但是,当我执行这段代码时,输出结果是错误的。
Original  Array : 5 4 7 2 1 9 3 6 10 8 
Sorted  Array : 1 4 5 2 6 7 3 8 9 10 

请问有人可以解释一下出了什么问题吗?我已经按照《算法导论》中给出的代码实现了,谢谢。

3个回答

14

不,你没有直接复制它 :) 我这里有它的副本...

for(int j=p; j<r-1; j++)
应该是这样的。
for(int j=p; j<r; j++)
或者
for(int j=p; j <= r-1; j++)

这本书写道:

for j = p to r - 1

这个值包含r - 1。请记住,书中的数组从1开始而不是0。因此,书中的算法通常应该小心谨慎地"复制",或者使用从1开始的数组。

编辑:有关评论的算法信息 书中的算法将最后一个元素作为枢轴。因此,对于已排序的数组来说,它将成为可怕的算法。它最终将以O(n ^ 2)结束,所以没有人应该在生产中使用这个算法(除非你知道自己在做什么和你的输入是什么),因为数组往往是稍微排好序的。Java内置的算法更加聪明,您可以在Javadoc中阅读有关它的信息。


感谢lasseespheholt的回答。我的书中包含伪代码,如下: for j = p to r-1。这是唯一的问题。 - Race
@竞赛:http://en.wikipedia.org/wiki/Quicksort有一个非常类似的算法,不过似乎您/教材中的算法将pivotIndex和left结合在一起。 - Merlyn Morgan-Graham
@Merlyn 请看编辑 :) 它使用最右边的元素,因此不需要额外的枢轴索引。 - Lasse Espeholt
1
这个实现需要注意的另一件事是输入边界。例如,正如答案中所强调的那样,由于选择了枢轴,几乎排序好的数据表现不佳。因此,如果您要求此实现在0 <= 50之间对100万个数字进行排序,您将遇到堆栈溢出(这在小数据集上不会显示)。 - Rich

1
提供一个Java中的另一种实现。它也基于相同的算法,并且还考虑了数组中的重复元素。
    public void sort( int[] inputArray, int lo, int high){
          int pivotIndex = partition(inputArray,lo,high);
         System. out .println("Got PivotIndex as " + pivotIndex);
          if (lo < pivotIndex -1)
                sort(inputArray,lo,pivotIndex - 1);
          if (pivotIndex+1 < high)
                sort(inputArray,pivotIndex+1,high);
          return ;
    }

    private int partition( int[] inputArray, int leftPtr,int rightPtr)
   {
         printArray(inputArray);
          int pivot = inputArray[leftPtr];
          while (leftPtr<rightPtr){
                 while (inputArray[leftPtr]<pivot)
                       leftPtr++;
                 while (inputArray[rightPtr]>pivot)
                       rightPtr--;
                 if (leftPtr<rightPtr)
                {
                       exchange(inputArray,leftPtr,rightPtr);

                          //Cases which have repeated numbers...
                        if (inputArray[leftPtr] == inputArray[rightPtr])
                             leftPtr++;
                }
         }
          return leftPtr;//return any one
   }

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接