Java中的Inplace Quicksort

为了刷新一些Java,我试图实现一个可以对整数数组进行排序的快速排序(inplace)算法。 以下是我到目前为止的代码。 你可以通过sort(a,0,a.length-1)来调用它。

如果两个’指针’ i,j指向与数据透视表具有相同值的数组条目,则此代码显然会失败(进入无限循环)。 pivot元素v始终是当前分区的最右侧(具有最大索引的分区)。

但我无法弄清楚如何避免这种情况,是否有人看到了解决方案?

 static void sort(int a[], int left, int right) { if (right > left){ int i=left, j=right-1, tmp; int v = a[right]; //pivot int counter = 0; do { while(a[i]0 && a[j]>v)j--; if( i < j){ tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } while(i < j); tmp = a[right]; a[right] = a[i]; a[i] = tmp; sort(a,left,i-1); sort(a,i+1,right); } } 

这应该工作( 稍微检查一下是否正确它有效 !):

编辑:我以前在错误检查中犯了一个错误。 我忘了添加2个条件,这里是修改后的代码。

 public static void main (String[] args) throws java.lang.Exception { int b[] = {10, 9, 8, 7, 7, 7, 7, 3, 2, 1}; sort(b,0,b.length-1); System.out.println(Arrays.toString(b)); } static void sort(int a[], int left, int right) { if (right > left){ int i=left, j=right, tmp; //we want j to be right, not right-1 since that leaves out a number during recursion int v = a[right]; //pivot do { while(a[i]v) //no need to check for 0, the right condition for recursion is the 2 if statements below. j--; if( i <= j){ //your code was i 

}

此代码在IDEOne在线编译器中

基本上我们确保如果i / j的值与pivot相同,我们也交换值,并突破递归。

还有一个伪代码检查长度,好像我们有一个只有1个项目的数组已经排序( 我们忘记了基本情况 ),我认为我们需要它,但是因为你传入了索引和整个数组,不是子arrays,我们只增加i和j所以算法不会坚持0(它们已经完成排序)但仍然保持排序1的数组:)

此外,我们必须添加2个条件来检查数组是否已经为递归调用排序。 没有它,我们将永远排序已排序的数组,因此另一个无限循环。 看看我如何添加检查,如果留下小于j,如果我不正确。 此外,在传递i和j的那一点上,我实际上是我们为分而治之分裂的中间指数,而j将是中间值之前的值。

它的伪代码取自RosettaCode :

 function quicksort(array) if length(array) > 1 pivot := select any element of array left := first index of array right := last index of array while left ≤ right while array[left] < pivot left := left + 1 while array[right] > pivot right := right - 1 if left ≤ right swap array[left] with array[right] left := left + 1 right := right - 1 quicksort(array from first index to right) quicksort(array from left to last index) 

参考:这个问题

另外阅读本文以便快速复习,它的实现与oridnary while循环不同

这很有趣:)

在预先形成Quicksort时,我强烈建议使用单独的分区方法来使代码更容易理解(我将在下面展示一个示例)。 除此之外,避免最坏情况运行时间的好方法是在执行快速排序之前对正在排序的arrays进行洗牌。 我还使用第一个索引作为分区项而不是最后一个。

例如:

 public static void sort (int[] a) { StdRandom.shuffle(a); sort(a, 0, a.length - 1); } private static void sort(int[] a, int lo, int hi) { if (hi <= lo) return; int j = partition(a, lo, hi) // the addition of a partitioning method sort(a, lo, j-1); sort(a, j+1, hi); } private static int partition(int[] a, int lo, int hi) { int i = lo, j = hi + 1, tmp = 0; int v = a[lo]; while (true) { while (a[i++] < v) if (i == hi) break; while (v < a[j--]) if (j == lo) break; if (i >= j) break; tmp = a[i]; a[i] = a[j]; a[j] = tmp; } tmp = a[lo]; a[lo] = a[j]; a[j] = temp; return j; } 

除此之外,如果你想要一个关于Quicksort如何工作的一个非常好的例子(作为复习),请看这里 。

下面是我编写的一些简单的代码,它不会初始化为许多指针并以简单的方式完成工作。

 public int[] quickSort(int[] x ){ quickSortWorker(x,0,x.length-1); return x; } private int[] quickSortWorker(int[] x, int lb, int ub){ if (lb>=ub) return x; int pivotIndex = lb; for (int i = lb+1 ; i<=ub; i++){ if (x[i]<=x[pivotIndex]){ swap(x,pivotIndex,i); swap(x,i,pivotIndex+1); pivotIndex++; } } quickSortWorker(x,lb,pivotIndex-1); quickSortWorker(x,pivotIndex+1,ub); return x; } private void swap(int[] x,int a, int b){ int tmp = x[a]; x[a]=x[b]; x[b]=tmp; }