Reputation: 23
I am trying to implement the quicksort algorithm in c++ as a project in a lecture. The program works fine when I exclude the pivot from the recursive calls, but sometimes causes a stack overflow error when i include the pivot in either of the recursive calls.
The program malfunctions only for a specific array size, but I can't figure out what relation they have with the errors. For example, the program malfunctions when I give 40, but works just fine for 50.
void quicksort(double* arr, int init, int fin) {
if (init == fin) return;
if (init == fin - 1) {
if (arr[init] > arr[fin]) {
double temp = arr[fin];
arr[fin] = arr[init];
arr[init] = temp;
}
return;
}
int smaller = init - 1;
double pivot = arr[fin];
for (int ind = init; ind < fin; ind++) {
if (arr[ind] < pivot) {
smaller++;
double temp = arr[ind];
arr[ind] = arr[smaller];
arr[smaller] = temp;
}
}
arr[fin] = arr[smaller + 1];
arr[smaller + 1] = pivot;
if(smaller>=init) quicksort(arr, init, smaller);
if(smaller+2<=fin) quicksort(arr, smaller + 2, fin);
return;
}
This is the code in question. It works fine when i put it this way, but causes errors when i replace
if(smaller+2<=fin) quicksort(arr, smaller + 2, fin);
with
if(smaller+1<=fin) quicksort(arr, smaller + 1, fin);
Upvotes: 2
Views: 120
Reputation: 47962
Another way to look at it. Suppose the selected pivot element is the smallest value in the partition. It will move to the beginning of the range.
[ 3 5 2 1 4] // supposed we select 3 as the pivot
[ 2 1 3 5 4] // after partitioning
[ 3 5 4] // the recursive call for the right "half"
If we select 3 as the pivot again, nothing changes in this range. And thus, when we recurse on the right "half" again, we're in exactly the same situation. We've not made any progress, so recursion will continue until the stack overflows.
Omitting the pivot from the ranges for the recursive calls guarantees we make progress and thus that the recursion will eventually terminate.
Upvotes: 0
Reputation: 183361
if(smaller+1<=fin)
is equivalent to if(true)
(since smaller+1
starts out as init
and is incremented at most fin-init
times), so any call with at least three elements will necessarily recurse at that line — and the recursive call may not accomplish anything, if (for example) all three elements are equal.
Upvotes: 2