# Lecture 07: QuickSort

### COSC 311 Algorithms, Fall 2022

$\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}} }$

## Announcements

1. Homework 1, Exercise 4
2. Collaboration and Exercise
3. Homework 2, Posted Sunday

1. QuickSort

## Picture so Far:

SelectionSort. $O(n^2)$ operations

• $O(n^2)$ comparisons
• $O(n)$ swaps

BubbleSort and InsertionSort. $O(n^2)$ operations

• $O(n^2)$ comparisons
• $O(n^2)$ swaps

MergeSort. $O(n \log n)$ operations

• $O(n \log n)$ comparisons
• $O(n \log n)$ modifications
• uses $O(n)$ space overhead

## Today

QuickSort: Divide by Value

## QuickSort: Another D&C Sort

Idea. Divide array $a$ by value

• choose a value $p$ from $a$, the pivot
• arrage values of $a$ such that:
• $p$ is at index $k$
• values $\leq p$ are at indices $i \leq k$
• values $> p$ are at indices $j > k$
• recursively sort indices $i < k$
• recursively sort indice $j > k$

## QuickSort Pseudocode

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 Method

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


## QuickSort Pseudocode

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)


## What is Worst-Case QS Running Time?

Assume $\mathrm{GetPivot}(a, i, j)$ returns a value in $a[i..j]$

• as with $\MergeSort$, total time at each depth of recursion is $O(n)$

## When is QS Running Time Better?

Best pivot selection?

## Acceptable Pivot Selection?

What if we canâ€™t get the best possible? What might still be acceptable?

## A Heuristic

A pivot $p$ is good if its rank is between $\frac 1 4 k$ and $\frac 3 4 k$

• $\implies$ larger recursive call has size at most $\frac 3 4 k$

## Depth with Good Pivots?

Question. How many good pivots until we reach a base case?

## Random Pivot Selection

GetPivot(a, i, j):
k <- RandomInt(i, j)
return a[k]


Question. How likely is it that a pivot is good?

## Heuristic

With random pivot selection

1. on average, half of pivots are good
2. on average, depth at most doubles

So running time is $O(n \log n)$ on average

## Careful Analysis

Can show. If random pivot is chosen, then on average QuickSort uses $O(n \log n)$ operations

• Formalizing previous argument is a bit tricky

• More clever and simpler analyses exist!

Homework 2!

## Next Time

• Lower bounds for sorting

• Lecture Ticket: Argue that every sorting algorithm uses $\Omega(n)$ operations