$ \def\compare{ {\mathrm{compare}} } \def\swap{ {\mathrm{swap}} } \def\sort{ {\mathrm{sort}} } \def\insert{ {\mathrm{insert}} } \def\true{ {\mathrm{true}} } \def\false{ {\mathrm{false}} } \def\BubbleSort{ {\mathrm{BubbleSort}} } \def\SelectionSort{ {\mathrm{SelectionSort}} } \def\Merge{ {\mathrm{Merge}} } \def\MergeSort{ {\mathrm{MergeSort}} } \def\QuickSort{ {\mathrm{QuickSort}} } \def\Split{ {\mathrm{Split}} } $
QuickSort(a, i, j):
if j - i <= 1 then
return
endif
p <- GetPivot(a, i, j) # select a pivot
k <- Split(a, i, j, p)
QuickSort(a, i, k-1)
QuickSort(a, k+1, j)
Split(a, i, j, p):
left <- i, right <- j
while left < right do
if a[left] > p and a[right] <= p then
swap(a, left, right)
left++, right--
else
if a[left] <= p then left++
if a[right] > p then right--
endif
endwhile
return right
What is the problem?
Split(a, i, j, pIndex):
pivot <- a[pIndex]
swap(a, pIndex, j); # move pivot to last index
small <- i - 1;
for cur in range i..j do
if a[cur] <= pivot then
small <- small + 1
swap(a, small, cur)
endif
endfor
return small
Invariants:
Question. Can we do better?
Sorting arrays of size $n$ requires $\Omega(n)$ operations.
Why?
Any algorithm that accesses and modifies arrays using only $\compare$ and $\swap$ operations requires $\Omega(n \log n)$ comparisons.
Consider. Arrays are permutations of $1,2,\ldots,n$
Main idea. $a$ and $b$ are distinct arrays and $A$ is an algorithm
$A$ distinguishes $a$ and $b$ if $A(a)$ and $A(b)$ both make a call to $\compare(\cdot, i, j)$ with $\compare(a, i, j) \neq \compare(a, i, j)$
if $A$ does not distinguish $a$ and $b$, then it does not sort both $a$ and $b$
If $A$ performs too few $\compare$ operations, then it cannot distinguish all arrays of size $n$
Consider:
Fixed sorting algorithm $A$
InsertionSort(a):
for i = 2 to n do
j <- i
while j > 1 and compare(a, j-1, j) do
swap(a, j, j-1)
endwhile
endfor
Fixed set of inputs of size $n$
Follow execution of $A$ on all inputs from $S_n$
Define a binary tree:
Form this tree for all comparisons made on all inputs in $S_n$
for i = 2 to n do
| j <- i
| while j > 1 and compare(a, j-1, j) do
| | swap(a, j, j-1)
Question. What does the depth of decision tree correspond to in terms of execution of $A$?
Question. If $A$ distinguishes $a$ and $b$, what can we say about nodes labeled with $a$ and $b$?
Claim. If $A$ does not distinguish $a$ and $b$ with $a \neq b$, then $A$ does not sort both $a$ and $b$.
Why?
Consequence. If $A$ sorts all arrays of size $n$, then every leaf of $A$’s decision tree is labeled with a single permutation array.
Why?
How many leaves must a correct decision tree have?
How deep must decion tree be?
Claim. $\log n! = \Omega(n \log n)$
Theorem. Any algorithm that sorts all permutations of size $n$ using only $\compare$ and $\swap$ operations requires $\Omega(n \log n)$ comparisons.
When can we sort faster than $O(n \log n)$?