int search(A,i,j,x)
{
if (i == j)
if(A[i] == x) return i;
else return -1;
int k = (i + j)/2;
int r = search(A,i,k,x);
if (r != -1)
return r;
else
return search(A,k+1,j,x);
}
The search(A,i,j,x) algorithm returns
-1 if x is not in A[i],...,A[j]. Otherwise it returns the
index in i..j at which the value of A is x. It does not
assume that its input is in sorted order. It divides the
range in equal halves (this is guaranteed, unlike quicksort),
looks first in the left half, then (if what it was searching
for wasn't there, looks in the right half.
In the following, assume there are no duplicates in A.
int partition(vector<int> &A, int i, int j, int x)
{
while(1)
{
while (j >= i && A[j] >= x)
j--;
while (A[i] < x)
i++;
if (i < j)
swap(A[i],A[j]);
else
return j;
}
}
void quicksort(vector<int> &A, int i, int j)
{
if (i == j) return;
int k = partition(A,i,j,A[i]);
if (k < i)
k = i;
quicksort(A,i,k);
quicksort(A,k+1,j);
}
When we tested this on random arrays of integers we found that
it was pretty fast. Certainly it didn't behave like
quicksort's worst case running time, which is Θ(n^2).
This leads us to the hypothesis that quicksort's average
running time is closer to its best-case, which is
Θ(n lg n).
| T(k) + T(n-k) | ≤ | a k lg k + a(n-k) lg(n-k) |
| ≤ | a k lg(n/2) + a (n-k) lg n, since k ≤ n/2 and n-k ≤ n | |
| ≤ | a k (lg n - lg 2) + a (n-k) lg n | |
| ≤ | a k lg n - a k + a (n-k) lg n | |
| ≤ | a lg n(k + n-k) - a k | |
| ≤ | a n lg n - a k |
Assumption: We assume that the expected time required for quicksort on input A,i,j is the same for a range i,j of random values as for a range i,j that resulted from a call to partition. I.e. partition preserves randomness in each of the partitions it returns.Quicksort calls partition, then recursively calls itself on the two partition sets, possibly correcting for the empty partition as discussed in class. So we will sum up the total work for quicksort on a range of n elements and determine that it is less than or equal to a n lg n as follows: