Quicksort, Randomized Algorithms

 

Today, we will introduce a very interesting Algorithm, called “Quicksort”, which was invented by Tony Hoare in 1962.

  • It’s also a Divide-and-Conquer Algorithm.

  • The array will be sorted “in place”. (That means Quicksort doesn’t need extra array like Mergesort.) Therefore, it’s fairly efficient in its use of storage.

  • Very pratical (with tuning)

Idea of Quicksort

  1. “Divide”: Partition array into 2 subarray arond pivot ${ x }$, such that
elems in lower subarray ${ \leq x \leq }$ elems in upper subarray

  1. “Conquer”: Recursively sort the two subarray.

  2. “Combine”: Trivial

So, the key point is te “Divide” Step. We can treat the Quicksort as recursive partitioning, and the Mergesort is recursive merging. Here, we can give a linear time ${ \Theta(n) }$ partiioning subroutine and give its pseoudocode

1
2
3
4
5
6
7
8
9
Partitioning(A,p,q): // treat A[p···q]
    x = A[p] // pivot is A[q]
    i = p // set index
    For j = p+1 to q
        if A[j] <= x 
            i = i + 1
            exchange A[i] with A[j]
    exchange A[p] with A[i]
    return i

Correctness of Quicksort

Actually, we hold our array with 4 area (but some of them maybe empty), which is also our “invariant”. The first area is the first element ${ x }$. And, all the elements of the second area is less than or equal to ${ x }$. The third area include some elements which are greater than ${ x }$. The last area is called “unknown area”, the elements in which are undecided.

In each loop, when we move to next element, we first compare it to ${ x }$, if it’s greater than ${ x }$, then we continue move forward. If not, we exchange it with the first element in third area (all the elements in it is greater than ${ x }$). So, in the second situation, the second area is entended by one element, and the hole third area move forward by one element.

When the index ${ j }$ move to ${ q }$. Then the unknown area is a empty set. At that time, we have three area: ${ x }$, second area (${ \leq x }$) and third area (${ \geq x }$).

In the end, we exchange the first element ${ A[p], x }$ with the last element of second area. We will find, all the elements which is less than ${ x }$ list in the left of ${ x }$, and the all the elements greater than ${ x }$ are positioned in the right of the ${ x }$.

It’s easy to check the runting time of “Partitioning” is ${ \Theta(n) }$.

Runing time Analysis

Then we can write down the pseudocode of Qiucksort

1
2
3
4
5
6
7
8
Quicksort(A,p,q): // treat A[p···q]
    if p < q
        r = Partition(A,p,q)
        Quicksort(A,p,r-1)
        Quicksort(A,r,q)

//Initial Call
Quicksort(A,1,n)

Worst-case analysis

Here, to analyze the runing time of Quicksort, we assume all the elements is distinct (not redundant). Let’s ${ T(n) }$ be the worst-case runing time. So, if the input array is sorted or reverse sorted, the partitioning is the worst case, becasue one side of the partition has no elements. Here we can right the recursion of Quicksort (the runting time of empty side is ${ T(0) }$, and the another side is ${ T(n-1) }$, the partition time is ${ \theta(n) }$)

$$ \begin{equation} \begin{aligned} T(n) &= T(0) + T(n-1) + \theta(n) \\ &= \theta(1) + T(n-1) + \Theta(n) \\ &= T(n-1) + \Theta(n) \\ &= \Theta(n^2) \end{aligned} \end{equation} $$

Best case Analysis

In general, we don’t do best-case analyses, but here we do it for intuition only. If we are in the lucky case, Partition splits the array ${ n/2 : n/2 }$. In this case, the recursion is

$$ \begin{equation} \begin{aligned} T(n) &= 2T(n/2) + \Theta(n) \\ &= \Theta(n \lg n) \end{aligned} \end{equation} $$

1:9 Split?

But, how about Split is always ${ 1/10 : 9/10 }$? We are in lucky or unlucky case? Let’s draw a recursion tree for this (denote ${ \Theta(n) }$ as ${ cn }$)

Form the recursion tree, we can observe the range of the running time is

$$ cn \cdot \log_{10} n + \Theta(n) \leq T(n) \leq cn \cdot \log_{10/9} n + \Theta(n) $$

And, we surprisingly find, ${ T(n) =\Theta( n \lg n )}$. We are in the lucky case!!

To prove it rigorously, we use Substitution Method to do it again. *** Recurrence is
$$ T(n) = T(n/10) + T(9n/10) + \Theta(n) $$
Guess: ${ T(n) = \Theta(n \lg n) }$ Induction: Assume ${ n < k }$ is correct Let ${ cn = \Theta(n) }$, and ${ c_1 = \frac{c}{\lg 10}, c_2 = \frac{c}{\lg 9/10} }$
$$ \begin{equation} c_1 n \lg n \leq T(n) \leq c_2 n \lg n \text{, for } n <k \end{equation} $$
Now, let's check ${ n \geq k }$
$$ T(n) = T(n/10) + T(9n/10) + \Theta(n) $$
By induction, we can get
$$ \begin{equation} \begin{aligned} T(n) &= T(n/10) + T(9n/10) + cn \\ & \geq c_1 \cdot \frac{n}{10} \cdot \lg \frac{n}{10} + c_1 \cdot \frac{9n}{10} \cdot \lg \frac{9n}{10} + cn \\ & \geq c_1 \cdot n \cdot \lg \frac{n}{10} + cn \\ & = (c_1 \cdot n \cdot \lg \frac{n}{10} - c_1 n \lg n + cn) + c_1 n \lg n \\ & = c_1 n \lg n \end{aligned} \end{equation} $$
For, the right side
$$ \begin{equation} \begin{aligned} T(n) &= T(n/10) + T(9n/10) + cn \\ & \leq c_2 \cdot \frac{n}{10} \cdot \lg \frac{n}{10} + c_2 \cdot \frac{9n}{10} \cdot \lg \frac{9n}{10} + cn \\ & \leq c_2 \cdot n \cdot \lg \frac{9n}{10} + cn \\ & = (c_2 \cdot n \cdot \lg \frac{9n}{10} - c_2 n \lg n + cn) + c_2 n \lg n \\ & = c_2 n \lg n \end{aligned} \end{equation} $$
***

Alternative partition

Suppose, we are alternatively in lucky and unlucky case. What’s happen? We can first wirte down the recurrences of Lucky (${ L(n) }$) and Unlucky case (${ U(n) }$)

$$ \begin{align} L(n) &= 2U(n/2) + \Theta(n) \\ U(n) &= L(n-1) + \Theta(n) \end{align} $$

Then, we can use the recurrence of ${ U(n/2) }$ plug in the ${ L(n) }$, that gives us

$$ \begin{equation} \begin{aligned} L(n) &= 2(L(n/2 -1)+ \Theta(n/2)) + \Theta(n) \\ & = 2L(n/2 -1) + \Theta(n)\\ & = \Theta(n \lg n) \end{aligned} \end{equation} $$
Actually, here is a little different with Master theorem, but here ${ -1 }$ doesn't influence the conclusion. We can prove it. *** Let ${ \Theta(n) = cn }$, by draw the recursion tree, we will find, in the ${ i^{th}, i>1 }$ level, the sum of nodes is ${ c(n - \sum_{j=1}^{i} 2^{j-1}) = c (n - 2^i + 2) }$. Now, we analyze the height of the tree. It's easy to get in the ${ i^{th} }$ level, the notes is ${ L\left(\frac{n}{2^{i-1}} - \sum_{j=0}^{i-2} \left(\frac{1}{2}\right)^j \right) }$. So, the height ${ h }$ satisfy
$$ \begin{equation} \begin{aligned} \frac{n}{2^{h-1}} - \sum_{j=0}^{h-2} \left(\frac{1}{2}\right)^j &= 1 \\ \frac{n}{2^{h-1}} -2 + \left(\frac{1}{2}\right)^{h-2} & = 1 \\ h &= \lg n - k \end{aligned} \end{equation} $$
Here, ${ k }$ is a constant, we don't need to care about its specified value. And, as above description, the sum of ${ i^{th} }$ level is ${ c (n - 2^i + 2) }$, so the total cost is
$$ \begin{equation} \begin{aligned} T(n) &= cn \cdot h - \sum_{i=1}^{h-1} 2^i + 2 \cdot h \\ &= \Theta(n\lg n) - 2^{\lg n -k} + 2 + \Theta(\lg n) \\ & = \Theta(n\lg n) - \Theta(n) + \Theta(\lg n) \\ & = \Theta(n\lg n) \end{aligned} \end{equation} $$
***

But anyway, even we are alternatively in lucky partition, we still have a ${ \Theta(n \lg n) }$ running time. Now, we proposed another question, how can we avoid unlucky case?

We can randonmly arrange the elements OR randomly choose the pivot!

Randonmized Quicksort

Here we choose the last way to do, becasue it’s easy to analyze the running time.

  • Pivot on random element (we swap the first element with some other element in the array before partition)

  • The running time is independent of the input ordering.

  • No assumptions about the input distribution.

  • No specific input can elicit the the worst-case behavior.

  • Worst-case determined only by random number generator.

Analysis of runing time

Let ${ T(n) }$ be the random variable for the runing time, assuming the random numbers are independent.

For a particular partition ${ k=0,1,\cdots, n-1 }$, we have the corresponding indicator random variable ${ x_k }$

$$ x_k = \begin{cases} 1, \text{ if partition generates } k : (n-k-1) \text{ split,} \\ 0, \text{ otherwise.} \end{cases} $$

So the expectation of ${ x_k }$ is

$$ \begin{equation} \begin{aligned} E\left[x_k \right] &= 0 \cdot P(x_k=0) + 1 \cdot P(x_k=1) \\ & = P(x_k=1) \\ & = \frac{1}{n} \end{aligned} \end{equation} $$

And the recurrence of ${ T(n) }$ is

$$ T(n) = \begin{cases} T(0)+T(n-1)+\Theta(n)&, \text{ if } 0 : (n-1) \text{ split,} \\ T(1)+T(n-2)+\Theta(n)&, \text{ if } 1 : (n-2) \text{ split,} \\ &\vdots \\ T(n-1)+T(1)+\Theta(n)&, \text{ if } (n-1) : 1 \text{ split.} \\ \end{cases} $$

Or we can use a little trick to treat the ${ T(n) }$ as following

$$ T(n) = \sum_{k=0}^{n-1} x_k \left(T(k)+T(n-k-1) +\Theta(n) \right) $$

Then, we gonna talk about the Expectation of ${ T(n) }$

$$ \begin{equation} \begin{aligned} E\left[T(n)\right] &= E\left[\sum_{k=0}^{n-1} x_k \left(T(k)+T(n-k-1) +\Theta(n) \right)\right] \\ & = \sum_{k=0}^{n-1} E\left[x_k \left(T(k)+T(n-k-1) +\Theta(n)\right)\right] \\ & = \sum_{k=0}^{n-1} E\left[x_k \right] \cdot E\left[T(k)+T(n-k-1) +\Theta(n)\right] \\ & = \frac{1}{n} \sum_{k=0}^{n-1} E\left[T(k)+T(n-k-1) +\Theta(n)\right] \\ & = \frac{1}{n} \sum_{k=0}^{n-1} E\left[T(k)\right]+ \frac{1}{n} \sum_{k=0}^{n-1} E\left[T(n-k-1)\right] + \frac{1}{n} \sum_{k=0}^{n-1} E\left[\Theta(n)\right] \end{aligned} \end{equation} $$

Here we need to notice that ${ \sum_{k=0}^{n-1} E\left[T(k)\right]=\sum_{k=0}^{n-1} E\left[T(n-k-1)\right] }$, they are just in different order. So, we can get

$$ \begin{equation} \begin{aligned} E\left[T(n)\right] & = \frac{1}{n} \sum_{k=0}^{n-1} E\left[T(k)\right]+ \frac{1}{n} \sum_{k=0}^{n-1} E\left[T(n-k-1)\right] + \frac{1}{n} \sum_{k=0}^{n-1} E\left[\Theta(n)\right] \\ & = \frac{2}{n} \sum_{k=0}^{n-1} E\left[T(k)\right]+ \Theta(n) \end{aligned} \end{equation} $$

For technical convenience, we want to absorb the ${ k=0,1 }$ terms in to ${ \Theta(n) }$. (Why we do that? We can get it in the following step). Actually, ${ E\left[T(1)\right], E\left[T(2)\right] }$ are just constants, so it can be absorb into ${ \Theta(n) }$, that is

$$ E\left[T(n)\right]= \frac{2}{n} \sum_{k=0}^{n-1} E\left[T(k)\right]+ \Theta(n) $$

So, we have done all the simplification for recurrence, now we solve it! We are going to prove ${ E\left[T(n)\right] \leq an\lg n }$ for some contant ${ a>0 }$. How can we do it?? Substitution Method!!

Choose ${ a }$ big enough so that ${ a n \lg n \geq E\left[T(n)\right]}$ for some small ${ n }$. (That’s the reason why we absorb ${ k=1,0 }$ items, because they will never make the cases work)

We will use the fact that

$$ \sum_{k=2}^{n-1} k \lg k \leq \frac{1}{2} n^2 \lg n - \frac{1}{8} n^2 $$
We can use intergration to prove this inequality. --- Due to ${ f(k) = k \lg k }$ is a increasing funtion. So, we can get
$$ \begin{equation} \begin{aligned} \sum_{k=2}^{n-1} k \lg k &< \int_{2}^{n-1} k \lg k dk \\ & = \left. \frac{k^2 \lg k}{2} - \frac{k^2}{4 \ln 2} \right \vert_{2}^{n-1} \\ & < \left. \frac{k^2 \lg k}{2} - \frac{k^2}{4 \ln 2} \right \vert_{2}^{n} \\ & < \frac{n^2 \lg n}{2} - \frac{n^2}{4 \ln 2} -1 \\ & < \frac{n^2 \lg n}{2} - \frac{n^2}{8} \end{aligned} \end{equation} $$
---

By assumption, the expectation of running time satisfies

$$ \begin{equation} \begin{aligned} E\left[T(n)\right] &= \frac{2}{n} \sum_{k=2}^{n-1} E\left[T(k)\right]+ \Theta(n) \\ & \leq \frac{2}{n} \sum_{k=2}^{n-1} ak \lg k+ \Theta(n) \end{aligned} \end{equation} $$

By use the fact above, we get

$$ \begin{equation} \begin{aligned} E\left[T(n)\right] & \leq \frac{2}{n} \sum_{k=2}^{n-1} ak \lg k+ \Theta(n) \\ & \leq \frac{2a}{n} \left( \frac{1}{2} n^2 \lg n - \frac{1}{8} n^2 \right) + \Theta(n) \\ &= a n \lg n- \left(\frac{an}{4} -\Theta(n) \right) \end{aligned} \end{equation} $$

Here, if ${ a }$ is big enough such that ${ \frac{an}{4} > \Theta(n) }$, we can get ${ E\left[T(n)\right] \leq a n \lg n}$.