仅当数组不是随机数组时,我的快速排序算法才对较大的n值失败。我试过在各种数组上使用该算法。当我使用数字的随机数组(对于n的任何值)时,它可以正常工作,但是对于包含相同值或以升序或降序排列的值的数组,它会失败。而且这也仅在n大约为6000左右时才有效。(当n为<5000时,它可以完美工作)
我已经尝试使用其他版本的quicksort。使用while循环而不是递归的循环,它可以完美地工作。就像我已经说过的那样,只有当非随机数组的n大于6000时,我的算法才会失败,对于5000或以下的算法,它会很好地工作。
void quicksort(int a[], int low, int high) {
if (low < high) {
int index = partition(a, low, high); // error
quicksort(a, low, index - 1); // error
quicksort(a, index + 1, high);
}
}
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low - 1;
//int j = low;
for (int j = low; j < high; j++) {
// If current element is smaller than or
// equal to pivot
if (arr[j] <= pivot) {
i++;
// swap arr[i] and arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return (i + 1);
}
上面有我的快速排序算法。在n> 6000(且数组不是随机的)中失败的那个。
下面是适用于n的所有值以及任何类型的数组的代码。
public void quicksort(int[] data, int low, int high)
{ // 1 or 0 items are sorted by default
if(high - low < 1)
return;
int left = low;
int right = high;
int pivot = data[low + (high - low) / 2];
while(left <= right)
{ // Increment left pointer until left >= pivot
while(data[left] < pivot)
left++;
// Increment right pointer until right <= pivot
while(data[right] > pivot)
right--;
// If left < right; swap values
if(left <= right)
{ int temp = data[left];
data[left] = data[right];
data[right] = temp;
left++;
right--;
}
}
// quick_sort 'lesser values'
quicksort(data, low, right);
// quick_sort 'greater values'
quicksort(data, left, high);
}
static int partition(int[] array, int low, int high) {
int j, temp, i = low + 1;
Random random = new Random();
int x = random.nextInt(high - low) + low;
temp = array[low];
array[low] = array[x];
array[x] = temp;
for (j = low + 1; j <= high; j++) {
if (array[j] <= array[low] && j != i) {
temp = array[j];
array[j] = array[i];
array[i++] = temp;
} else if (array[j] <= array[low]) {
i++;
}
}
temp = array[i - 1];
array[i - 1] = array[low];
array[low] = temp;
return i - 1;
}
终端在两行中特别显示错误。 (我在第一个quicksort方法中标记为错误的行)。
答案 0 :(得分:1)
如果数据已经按顺序排列,则使用arr [high](或arr [low])会导致最坏情况下O(n)的堆栈空间开销,从而使堆栈溢出。第二个示例使用中间元素(arr [low +(high-low)/ 2]),这对于已排序的数据或已反向排序的数据将具有最佳的堆栈空间开销。
一种将堆栈空间开销限制为O(log(n))的解决方法是在进行分区之后,检查哪个部分较小,并且仅对较小的部分使用递归,然后循环返回以处理较大的部分(根据需要更新为低或高,以在循环返回之前排除现在已排序的较小部分。
public static void quicksort(int[] arr, int low, int high)
{
while (low < high) {
int index = partition(arr, low, high);
if((index-low) <= (high-index)){ // avoid stack overflow
quicksort(arr, low, index - 1); //
low = index+1; //
}else{ //
quicksort(arr, index + 1, high); //
high = index-1; //
} //
}
}
public static int partition(int[] arr, int low, int high)
{
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
int tmp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = tmp;
return (i + 1);
}
如果有兴趣,Hoare分区方案会更快:
public static void qsort(int[] a, int lo, int hi)
{
while(lo < hi){
int md = lo+(hi-lo)/2;
int ll = lo-1;
int hh = hi+1;
int p = a[md];
int t;
while(true){
while(a[++ll] < p);
while(a[--hh] > p);
if(ll >= hh)
break;
t = a[ll];
a[ll] = a[hh];
a[hh] = t;
}
ll = hh++;
if((ll - lo) <= (hi - hh)){
qsort(a, lo, ll);
lo = hh;
} else {
qsort(a, hh, hi);
hi = ll;
}
}
}