Today's Material: - Divide & Conquer (Recursive) Sorting Algorithms
Today's Material: - Divide & Conquer (Recursive) Sorting Algorithms
• External Sorting
1
Divide and Conquer Without Extra Space?
• Mergesort requires temporary array for
merging = O(N) extra space
• Can we do in place sorting without extra space?
• Want a divide and conquer strategy that does not
use the O(N) extra space
• Quicksort – Idea:
• Partition the array such that Elements in left sub-
array < elements in right sub-array.
• Recursively sort left and right sub-arrays
2
How do we Partition the Array?
• Choose an element from the array as the pivot
• Move all elements < pivot into left sub-array
and all elements > pivot into right sub-array
• E.g.,
7 18 2 15 9 11
• Suppose pivot = 7
• Left subarray = 2
• Right sub-array = 18 15 9 11
3
Quicksort
• Quicksort Algorithm:
1. Partition array into left and right sub-arrays such
that: Elements in left sub-array < elements in right
sub-array
2. Recursively sort left and right sub-arrays
3. Concatenate left and right sub-arrays with pivot in
middle
• How to Partition the Array:
• Choose an element from the array as the pivot
• Move all elements < pivot into left sub-array and all
elements > pivot into right sub-array
• Pivot?
• One choice: use first element in array 4
Quicksort Example
• Sort the array containing:
9 16 4 15 2 5 17 1
Pivot
Partition 4251 < 9 < 16 15 17
Partition 21 4 5 15 16 17
Concatenate 1 2 5 15 17
1 2 4 5 15 16 17
Concatenate
Concatenate 1 2 4 5 9 15 16 17
5
Partitioning In Place
• Seems like we need an extra array for partitioning and
concatenating left/right sub-arrays
• No!
• Algorithm for In Place Partitioning:
1. pivot=A[0]
2. Set pointers i and j to the beginning and the end of the array
3. Increment i until you hit an element A[i] > pivot
4. Decrement j until you hit an element A[j] < pivot
5. Swap A[i] and A[j]
6. Repeat until i and j cross (i exceeds or equals j)
7. Restore the pivot by swapping A[0] with A[j]
i j
Swap
Swap A[i] and A[j] 9 1 5 2 15
4 15 5 17 16
i i j j
Swap
Partitioning Complete 2 1 4 5 9 15 17 16
<=9 >=9 7
Partition Algorithm
int Partition(int A[], int N){
if (N<=1) return 0;
int pivot = A[0]; // Pivot is the first element
int i=1, j=N-1;
while (1){
while (A[j]>pivot) j--; // Move j
while (A[i]<pivot && i<j) i++; // Move i
if (i>=j) break;
Swap(&A[i], &A[j]);
i++; j--;
} //end-while
8
Pivotal Role of Pivots
• How do we pick the pivot for each partition?
– Pivot choice can make a big difference in run time
10
Median-of-Three Pivots
• Find the median of the first, middle and last element
2 4 9 15 16 5 4 2 15 16
9 5
42 71 10 14 81 63 38 27 56 95 After MedianOf3
i j
42 27
71 10 14 81 63 38 71
27 56 95 Need to swap 71 & 27
i j
42 27 10 14 38
81 63 81
38 71 56 95 Need to swap 81 & 38
i j
42 27 10 14 38 56
63 81 71 63
56 95 Swap A[i]=63 & pivot=56
j i
42 27 10 14 38 56 81 71 63 95 After Partition 12
<= 56 >= 56
MedianOf3 Algorithm
// Assumes N>=3
int MedianOf3(int A[], int N){
int left = 0;
int right = N-1;
int center = (left+right)/2;
13
Partition with MedianOf3
// Assumes N>=3
int Partition(int A[], int N){
int pivot = MedianOf3(A, 0, N-1);
return i;
} //end-Partition
14
QuickSort Performance Analysis
• Best Case Performance: Algorithm always
chooses best pivot and keeps splitting sub-
arrays in half at each recursion
– T(0) = T(1) = O(1) (constant time if 0 or 1 element)
– For N > 1, 2 recursive calls + linear time for
partitioning
– Recurrence Relation for T(N) = 2T(N/2) + O(N)
– Big-Oh function for T(N) = O(N logN)
15
QuickSort Performance Analysis
• Worst Case Performance: Algorithm keeps
picking the worst pivot – one sub-array empty
at each recursion
– T(0) = T(1) = O(1)
– T(N) = T(N-1) + O(N)
– T(N-2) + O(N-1) + O(N) = …
– T(0) + O(1) + … + O(N)
– T(N) = O(N2 )
8-Way Merging
17
8GB sorted data
External Sorting Running Time
• Assume you have N bytes to sort
• Further assume that your memory is M bytes