Reputation: 2262
I have been trying to implement the Hoare partitioning method, but neither I, nor the computer can't seem to understand it as it is written in Cormen and Wikipedia. The algorithm in both sources looks like this:
algorithm partition(A, lo, hi) is
pivot := A[lo]
i := lo - 1
j := hi + 1
loop forever
do
j := j - 1
while A[j] > pivot
do
i := i + 1
while A[i] < pivot
if i < j then
swap A[i] with A[j]
else
return j
For the following array: 9 3 11 55 4 , after partitioning it with the above function, it will look like this: 4 3 11 55 9 and the pivot index will be 2 which is completely false. Firstly, 9 and 4 will be swapped, so i will become 2 and j will become 4. But, during the next iteration, because of the do while loop, 9 will be skipped and will never ever be swapped again. Is there a problem with my thinking? (I think that my implementation in C++ doesn't have any mistakes)
#include <iostream>
using namespace std;
int a[100];
int partitie(int st, int dr){
int i,j,x;
x=a[st];
i=st-1;
j=dr+1;
while(true){
do{
j--;
}while(a[j]>x);
do{
i++;
}while(a[i]<x);
if(i<j) swap(a[i],a[j]);
else return j;
}
}
int main() {
int i,n;
cin>>n;
for(i=1;i<=n;i++) cin>>a[i];
cout<<partitie(1,n)<<endl;
for(i=1;i<=n;i++) cout<<a[i]<<" ";
return 0;
}
Upvotes: 0
Views: 1324
Reputation: 28826
You need to use the correct quicksort routine, since Hoare splits an array into left part and right part, unlike Lomuto which splits an array into left part, pivot, right part.
algorithm quicksort(A, lo, hi) is
if lo < hi then
p := partition(A, lo, hi)
quicksort(A, lo, p) // not quicksort(A, lo, p-1)
quicksort(A, p + 1, hi)
also choosing a pivot in the middle means that an already sorted or reverse sorted array is sorted quickly as opposed to being worst case:
pivot := A[lo+(hi-lo)/2] // or := A[(lo+hi)/2] if overflow not an issue
There would still be worst case patterns, but at least the simple ones are handled. Median of 3 is a bit slower, but reduces the number of worst case patterns:
md = lo + (hi-lo)/2
if (A[lo] > A[hi])
swap(A[lo], A[hi])
if (A[lo] > A[md])
swap(A[lo], A[md])
if (A[md] > A[hi])
swap(A[md], A[hi])
pivot := a[md]
Perhaps what you're looking for is quick select to find the kth element where k = array size / 2. It's similar to quick sort, but it only recursively searches the left or right part of the array that contains the kth element. Wiki article:
http://en.wikipedia.org/wiki/Quickselect
Upvotes: 1