我一直在尝试修复这个递归快速排序程序大约三天,我相信它有错误,因为它对较小的数组进行排序,但错误地对较大的数组进行排序。
代码使用三位中值技术从a[start] to a[end]
对数组进行排序。我认为问题在于分区。请看看
import java.util.*;
public class QuickSort
{
public static void main(String [] args)
{
int [] arr = {6,4,1,14, 13,20,7,10,9,2,17};
System.out.println(Arrays.toString(arr));
quickSort(arr, 0,arr.length-1);
System.out.println(Arrays.toString(arr));
System.out.println("is the array sorted? " + isSorted(arr));
}
public static void quickSort(int[] a, int start, int end)
{
if(end-start > 0) //base case for zero or one element?
{
int pivotPosn = partition(a,start,end);
quickSort(a,start, pivotPosn-1);
quickSort(a,pivotPosn+1, end);
}
}
/***
* swap - Swaps two values in an array.
***/
private static void swap(int [] a, int index1, int index2)
{
int temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
private static boolean isSorted(int [] a)
{
int i = a.length;
boolean result = true;
for(int j = 1; j<i; j++)
{
if(a[j-1] > a[j])
{
result = false;
}
}
return result;
}
private static int medianOfThreeIndex(int [] a, int start, int end)
{
int mid= start + (end-start)/2; //find the middle of the array
int vs = a[start];
int vm = a[mid];
int ve = a[end];
if (vs >= vm && vm >= ve)
{
return mid;
}
else if (vm >= vs && vs >= ve)
{
return start;
}
else
{
return end;
}
}
private static int partition(int [] a, int start, int end)
{
int boundary,pivot,pivotPosn;
pivotPosn = medianOfThreeIndex(a,start,end);
pivot = a[pivotPosn];
boundary = start;
swap(a,pivotPosn,end);//moving pivot to the right
for(int curr = start+1; curr<=end;curr++)
{
if(a[curr]<pivot)
{
boundary++;
swap(a,boundary,curr);
}
}
swap(a,end,boundary); //swap pivot value back to its final place
return boundary;
}
}
输出为[6, 4, 1, 9, 7, 13, 14, 10, 17, 20, 2]
我不知道我做错了什么:(
答案 0 :(得分:4)
你有几个错误,主要是我不认为你已经完全理解三位的中位数应该做什么以及在哪里使用它。特别是 - 它应该用于选择枢轴,而不是在阵列上进行任何交换。我假设你的交换方法正常工作。
你可以先忘掉三个枢轴选择的中位数,然后让你的程序的主要部分工作。三个枢轴选择的中位数只是为了提高性能,而不是选择数组的起点作为枢轴。所以,让我们改变你的代码来做到这一点:
private static int partition(int [] a, int start, int end)
{
int boundary,pivotPosn, pivot,bigStart;
pivotPosn = start;
pivot = a[pivotPosn];
boundary = start;
//Got rid of bigStart - it's not needed...
swap(a,pivotPos,end); //Move your pivot value to the "right" or end of array
// Note - it is fine to store the pivot at the "left" or start as
// the OP originally did - in which case the following for
// loop should run from start+1 to end inclusive and the
// boundary++ would come before the swap.
for(int curr = start; curr<end;curr++)
{
if(a[curr]<pivot)
{
swap(a,boundary,curr);
boundary++;
}
}
swap(a,end,boundary); //swap your pivot value back to its final place
return boundary;
}
然后看看你的快速排序方法。请记住,我们暂时忽略medianOfThree。你抓住了一个你真正不需要的边缘案例 - 2个成员阵列。更简单的是:
public static void quickSort(int[] a, int start, int end)
{
if(end-start > 0) //base case for zero or one element? already
{
int pivotPosn = partition(a,start,end);
quickSort(a,start, pivotPosn-1);
quickSort(a,pivotPosn+1, end);
}
}
有了它,它将起作用:)
然而 - 你可能想回到medianOfThree。还记得我们放置pivotPosn = start
的位置吗?
将其更改为pivotPosn = medianOfThree(a,start,end);
(或任何您喜欢的内容,只要它在数组中播放)。
medianOfThree然后需要从数组的开始,中间和结尾返回中值的索引。我建议改变你的方法(不是最紧凑,但易于阅读):
private static int medianOfThreeIndex(int [] a, int start, int end)
{
int mid= start + (end-start)/2; //find the middle of the array
int vs = a[start];
int vm = a[mid];
int ve = a[end];
if (vs >= vm && vm >= ve)
{
return mid;
}
else if (vm >= vs && vs >= ve)
{
return start;
}
else
{
return end;
}
}
有了这个 - 你完成了。我查看了一个教程,以防你不清楚算法并发现the Wikipedia article on this is pretty good.
答案 1 :(得分:0)
你的代码对我来说很奇怪。看看http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html 那里的代码对我来说似乎更清楚。