Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
An outline of the quick sort algorithm, including its implementation, running time analysis, and improvements such as tail recursion removal and pivot selection strategies. It covers the partition function, the best, average, and worst-case running times, and the intuition behind the performance of quick sort compared to other sorting algorithms.
Typology: Study notes
1 / 18
This page cannot be seen from the preview
Don't miss anything!
Outline
Today:
Quick Sort
Like mergesort, it is a divide-and-conquer algorithm
Mergesort: easy division, complex combination
mergesort(left half) mergesort(right half) merge(left, right)
Quicksort: complex division, easy combination
partition(left, right) quicksort(left partition) quicksort(right partition)
Partition [Lomuto]
int partition(int a, left, right) { int i, j, pivot; pivot = a[left]; for (i = left, j = i+1; j < right; j++) { / continue to look for elt < pivot / if (a[j] < pivot) { i++; / swap with first >= elt / swap(a[i], a[j]); } } / put pivot in place, swap with last elt < pivot */ swap(a[left], a[i]); return i; }
Running time:
Running Time of Quicksort
Think of it as building a binary tree
Best case:
Worst case: when array is pre-sorted
Average case: O(N log N )
Quicksort is In-place, but...
Recursion uses up stack space Worst case needs Θ(N ) stack space
Small list:
Quicksort is not stable
Tail-Recursion Removal
Tail recursion:
Examples:
int count(link *list) { if (!list) return 0; return 1+count(list->next); }
void walk(link *list) { if (!list) return; visit(list); walk(list->next); } void reverse_walk(link *list) { if (!list) return; reverse_walk(list->next); visit(list); }
Improved Quicksort
void qsort(int *a, left, right) { qsort_tr(a, left, right); isort(a, right-left); }
void qsort_tr(int a, left, right) { while (right-left > smallsize) { split = partition(a, left, right); if (split < ((left+right) >> 1)) { qsort_tr(a, left, split-1); left = split+1; / right stays / } else { qsort_tr(a, split+1, right); right = split-1; / left stays */ } } return; }
Running Times of Sorting Algorithms
Algorithm Best Average Worst Linear insertion O(n) O(n^2 ) O(n^2 ) Binary insertion O(n log n) O(n^2 ) O(n^2 ) Bubble O(n^2 ) O(n^2 ) O(n^2 ) Quicksort O(n log n) O(n log n) O(n^2 ) Straight selection O(n^2 ) O(n^2 ) O(n^2 ) Heapsort O(n log n) O(n log n) O(n log n) Mergesort O(n log n) O(n log n) O(n log n)
Decision Tree and The Information Theoretic Lower Bound
Is O(n log n) the best we can do? Yes, if we use binary comparison on the key values
N elements in a decision tree result in N! permutations of the elements at the leaves (see Preiss Fig. 15.11). Let h be the height of tree:
2 h^ = N! h = dlog N !e dlog N !e ≥ log 2 N! ≥ log 2 (1 · 2 · 3 ·... · N ) ≥
∑^ N i=
log 2 i
≥ log 2 1 + log 2 2 + log 2 3 +... log 2 N 2 +... + N ≥ N 2 log 2 N 2 = Ω(N log N )
Distribution/Digital Sort
To escape the Information Theoretic Lower bound, instead of comparing keys, use them as data:
Radix Sort
Useful when key values are large but consist of base/radix (e.g., digits or chars) that each can be sorted using bucket sort Examples:
Algorithm:
Example: sort CX AX BZ BY AZ BX AY
Radix Sort
Running time: