My quicksort algorithm fails for larger values of n, and only if the array is not random. I've tried using the algorithm on various arrays. It works fine when I use a random array of numbers (for any value of n), but for an array that contains the same values or values in ascending order or descending order, It fails. And that too only when n is approximately abov 6000. ( It works perfectly when n is <5000)
I've already tried using a different version of quicksort. One that uses a while loop instead of recursion, and it works perfectly. And like I've said already my algorithm fails only when n is greater than 6000 for a nonrandomized array, for 5000 or below it works well.
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);
}
Above I have my quicksort algorithm. The one that fails for n>6000( and when the array is not random).
And below is the code that worked for all values of n and on any type of array.
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;
}
The terminal shows an error in two lines specifically. (The lines that I have marked as an error in the first quicksort method).
If the data is already in order, then using arr[high] (or arr[low]) results in worst case stack space overhead of O(n), which overflows the stack. The second example, uses the middle element (arr[low + (high-low)/2]), which will have best case stack space overhead for data already sorted or data already reverse sorted.
A workaround to limit stack space overhead to O(log(n)), is after doing partition, check to see which part is smaller, and only use recursion on the smaller part, then loop back to handle the larger part (update low or high as needed to exclude the now sorted smaller part before looping back).
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);
}
If interested, Hoare partition scheme is faster:
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;
}
}
}