Ex: Student records in a university
| Last | Sct | Grade | Phone | Dorm |
|---|---|---|---|---|
| Chen | 3 | A | 991-878-4944 | 308 Blair |
| Rohde | 2 | A | 232-343-5555 | 343 Forbes |
| Gazsi | 4 | B | 766-093-9873 | 101 Brown |
| Furia | 1 | A | 766-093-9873 | 101 Brown |
| Kanaga | 3 | B | 898-122-9643 | 22 Brown |
| Andrews | 3 | A | 664-480-0023 | 97 Little |
| Battle | 4 | C | 874-088-1212 | 121 Whitman |
Item: a row in the table
| Furia | 1 | A | 766-093-9873 | 101 Brown |
Key: a specific entry of an item that may or may not be unique
| Furia |
1 | A | 766-093-9873 | 101 Brown |
Sort: Rearrange array of \(N\) items into ascending order





Goal: Sort any type of data
Goal: Sort any type of data for which sorting is well defined
A total order is a binary relation \(\leq\) that satisfies
| Antisymmetry | if both \(v \leq w\) and \(w \leq v\), then \(v = w\) |
| Transitivity | if both \(v \leq w\) and \(w \leq x\), then \(v \leq x\) |
| Totality | either \(v \leq w\) or \(w \leq v\) or both |
Ex:
Is-Related-To violates antisymmetry
![]() |
![]() |
| Jon | Is-Related-To | Tobin |
| Tobin | Is-Related-To | Jon |
| except... | ||
| Jon | is not equal to | Tobin |
Rock-Paper-Scissors violates transitivity

\[\begin{array}{c} \textrm{rock} < \textrm{paper} \quad\textit{and}\quad \textrm{paper} < \textrm{scissors} \\ \textit{but}\quad \textrm{rock} \cancel< \textrm{scissors} \end{array}\]
CSE course prerequisites violate totality

\[\begin{array}{c} \textrm{cos120} \leq \textrm{cos121} \quad\textit{and}\quad \textrm{cos121} \leq \textrm{cos265} \quad\textit{and}\quad \ldots \\ \textit{but}\quad \textrm{cos320} \overset{?}{\leq} \textrm{cos350} \quad\textit{or}\quad \textrm{cos350} \overset{?}{\leq} \textrm{cos320} \end{array}\]
Goal: Sort any type of data for which sorting is well defined
Q. How can sort() know how to compare data without any information about the type of an item's key?
Double, String, java.io.File, pancakes?Use compareTo() callback (Reference to executable code)
sort() functionsort() calls object's compareTo() method as neededImplementing callbacks
| Java | interfaces |
| C | function pointers |
| C++ | class-type functors |
| C# | delegates |
| Python | first-class functions |
| Perl | first-class functions |
| Javascript | first-class functions |
| ML | ⋮ |
| ⋮ | ⋮ |
client code
public class StringSorter {
public static void main(String[] args) {
String[] a = StdIn.readAllStrings();
Insertion.sort(a); // <- defined soon...
for(int i = 0; i < a.length; i++) StdOut.println(a[i]);
}
}
Comparable interface (built into Java)
public interface Comparable<Item> {
public int compareTo(Item that);
}
String data-type implementation (built into Java)
public class String implements Comparable<String> {
/* ... */
public int compareTo(String that) {
/* if this < that, return <0 */
/* if this == that, return =0 */
/* if this > that, return >0 */
}
}
sort implementation (discussed soon...)
public class Insertion {
public static void sort(Comparable[] a) {
int N = a.length;
for(int i = 0; i < N; i++)
for(int j = i; j > 0; j--)
// vvvvvvvvvvvvvvvvvvvvvv
if(a[j].compareTo(a[j-1]) < 0) exch(a, j, j-1);
// ^^^^^^^^^^^^^^^^^^^^^^
// key point: no dependence on String data type!
else break;
}
}
Implement compareTo() so that v.compareTo(w)
v is less than wv is equal to wv is greater than wnull)if(v < w) return -1; // or ANY negative number if(v == w) return 0; if(v > w) return +1; // or ANY positive number
Built-in comparable types: Integer, Double, String, Date, File, ...
User-defined comparable types: implement the Comparable interface
Comparable interfaceDate data type (simplified version of java.util.Date)
public class Date implements Comparable<Date> {
// ^^^^^^
// only compares dates to other dates
private final int month, day, year;
public Date(int m, int d, int y) {
month = m;
day = d;
year = y;
}
public int compareTo(Date that) {
if(this.year < that.year ) return -100;
if(this.year > that.year ) return +100;
if(this.month < that.month) return -10;
if(this.month > that.month) return +10;
if(this.day < that.day ) return -1;
if(this.day > that.day ) return +1;
return 0;
}
}
i, find index min of smallest remaining entrya[i] and a[min]
Algorithm: ↑ scans from left to right
Invariants
| X | X | X | |||||||||||||
| X | X | X | X | X | |||||||||||
| X | X | X | X | X | X | X | |||||||||
| X | X | X | X | X | X | X | X | X | X | ||||||
| X | X | X | X | X | X | X | X | X | X | X | |||||
| X | X | X | X | X | X | X | X | X | X | X | X | X | X | ||
| X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X |
| 1 | 1 | 2 | 2 | 2 | 3 | 4 | 4 | 7 | 6 | 6 | 7 | 5 | 5 | 4 | 7 |
| ↑ |
Helper functions: Refer to data through compares and exchanges
Less: is item v less than w?
private static boolean less(Comparable v, Comparable w) {
return v.compareTo(w) < 0; // note: NOT checking if == -1
}
Exchange: swap item in array a[] at index i with one at index j
private static void exch(Comparable[] a, int i, int j) {
Comparable swap = a[i];
a[i] = a[j];
a[j] = swap;
}
To maintain algorithm invariants:
// 1
i++;
// 2
int min = i;
for(int j = i+1; i < N; j++)
if(less(a[j], a[min])) min = j;
// 3
exch(a, i, min);
public class Selection {
public static void sort(Comparable[] a) {
int N = a.length;
for(int i = 0; i < N; i++) {
int min = i;
for(int j = i+1; j < N; j++)
if(less(a[j], a[min])) min = j;
exch(a, i, min);
}
}
private static boolean less(Comparable v, Comparable w)
{ /* as before */ }
private static void exch(Comparable[] a, int i, int j)
{ /* as before */ }
}
![]() |
![]() |
![]() |
![]() |
Key:
Proposition: Selection sort uses
Running time insensitive to input: Quadratic time, even if input is sorted
Data movement is minimal: Linear number of exchanges
i, swap a[i] with each larger entry to its left
Algorithm: ↑ scans from left to right
Invariants
| X | X | ||||||||||||||
| X | X | X | X | ||||||||||||
| X | X | X | X | X | X | ||||||||||
| X | X | X | X | X | X | X | X | X | |||||||
| X | X | X | X | X | X | X | X | X | X | ||||||
| X | X | X | X | X | X | X | X | X | X | X | X | X | |||
| X | X | X | X | X | X | X | X | X | X | X | X | X | X | X | X |
| 1 | 1 | 2 | 4 | 5 | 7 | 3 | 6 | 1 | 4 | 6 | 7 | 2 | 5 | 4 | 2 |
| ↑ |
To maintain algorithm invariants:
a[j] with each larger entry to its left// 1
i++;
// 2
for(int j = i; j > 0; j--)
if(less(a[j], a[j-1])) exch(a, j, j-1);
else break;
public class Insertion {
public static void sort(Comparable[] a) {
int N = a.length;
for(int i = 0; i < N; i++)
for(int j = i; j > 0; j--)
if(less(a[j], a[j-1])) exch(a, j, j-1);
else break;
}
private static boolean less(Comparable v, Comparable w)
{ /* as before */ }
private static void exch(Comparable[] a, int i, int j)
{ /* as before */ }
}
![]() |
![]() |
![]() |
![]() |
Key:
Proposition: To sort a randomly-ordered array with distinct keys, on average insertion sort uses
Pf: Expect each entry to move halfway back.

Best case: If the array is in ascending order, insertion sort makes \(N-1\) compares and \(0\) exchanges.
A E E L M O P R S T X
Worst case: if the array is in descending order (and no duplicates), insertion sort makes \(\sim \frac{1}{2} N^2\) compares and \(\sim \frac{1}{2} N^2\) exchanges.
X T S R P O M L F E A
Def: An inversion is a pair of keys that are out of order
A E E L M O T R X P S
Above has 6 inversions: T-R, T-P, T-S, R-P, X-P, X-S
Def: An array is partially sorted if the number of inversions is \(\leq cN\)
Proposition: For partially-sorted arrays, insertion sort runs in linear time
Pf: Number of exchanges equals the number of inversions (num of compares = exchanges + \((N-1)\))
Half exchanges: Shift items over (instead of exchanging)
less() and exch() to access data v
A C H H I M N N P Q X Y K B I N A R Y
\ \ \ \ \ \ \
A C H H I M M N N P Q X Y B I N A R Y
v
A C H H I K M N N P Q X Y B I N A R Y
Binary insertion sort: Use binary search to find insertion point
| | v |A C H H I M N N P Q X Y| K B I N A R Y | binary search for | \ first key > K /
Idea: Move entries more than one position at a time by \(h\)-sorting the array
An \(h\)-sorted array is \(h\) interleaved sorted subsequences
h = 4 input: L E E A M H L E P S O L T S X R group0: L ----- M ----- P ----- T group1: E ----- H ----- S ----- S group2: E ----- L ----- O ----- X group3: A ----- E ----- L ----- R
Shellsort [Shell 1959]: \(h\)-sort array for decreasing sequence of values of \(h\)
input: S H E L L S O R T E X A M P L E 13-sort: P H E L L S O R T E X A M S L E 4-sort: L E E A M H L E P S O L T S X R 1-sort: A E E E H L L L M O P R S S T X
i, swap a[i] with each larger entry h positions to its left
Q. How to \(h\)-sort an array?
Q. Why insertion sort?
public class Shell {
public static void sort(Comparable[] a) {
int N = a.length;
int h = 1;
while(h < N/3) h = 3*h + 1; // 1, 4, 13, 40, 121, 364, ...
while(h >= 1) {
for(int i = h; i < N; i++) {
for(int j = i; j >= h && less(a[j], a[j-h]); j -= h)
exch(a, j, j-h);
}
h = h / 3;
}
}
private static boolean less(Comparable v, Comparable w)
{ /* as before */ }
private static void exch(Comparable[] a, int i, int j)
{ /* as before */ }
}
![]() |
![]() |
![]() |
![]() |
Key:
Which is the best increment sequence to use?
Powers of two? 1, 2, 4, 8, 16, 32, ...
Which is the best increment sequence to use?
Powers of two? 1, 2, 4, 8, 16, 32, ...
Powers of two minus one? 1, 3, 7, 15, 31, 63, ...
Which is the best increment sequence to use?
Powers of two? 1, 2, 4, 8, 16, 32, ...
Powers of two minus one? 1, 3, 7, 15, 31, 63, ...
\(3x + 1\)? 1, 4, 13, 40, 121, 364, ...
Which is the best increment sequence to use?
Powers of two? 1, 2, 4, 8, 16, 32, ...
Powers of two minus one? 1, 3, 7, 15, 31, 63, ...
\(3x + 1\)? 1, 4, 13, 40, 121, 364, ...
Sedgewick: 1, 5, 19, 41, 109, 209, 505, 929, 2161, 3905, ...
(merging of \((9\cdot4^i) - (9\cdot2^i) + 1\) and \(4^i - (3\cdot2^i)+1\))
Proposition: An \(h\)-sorted array remains \(h\)-sorted after \(g\)-sorting it.
7-sort: S O R T E X A M P L E -- 3-sort: M O L E E X A S P R T
M S / E M
. P | E O
L R | . X
E T / A E M
M O L E E X A S P R T -- . . S
^ ^ . P X
| | . . . R
7-sorted . . . T
A E L E O P M S X R T
^ ^
| |
still 7-sorted!
Challenge: Prove this fact—it's more subtle than you'd think!
Proposition: The order of growth of the worst-case number of compares used by shellsort with the \(3x+1\) increments is \(N^{3/2}\).
Property: The expected number of compares to shellsort a randomly-ordered array using \(3x+1\) increment is...
| \(N\) | compares | \(2.5 N \ln N\) | \(0.25 N \ln^2 N\) | \(N^{1.3}\) |
|---|---|---|---|---|
| 5k | 93k | 106k | 91k | 64k |
| 10k | 209k | 230k | 213k | 158k |
| 20k | 467k | 495k | 290k | 390k |
| 40k | 1022k | 1059k | 1122k | 960k |
| 80k | 2266k | 2258k | 2549k | 2366k |
Important
Accurate model has not yet been discovered (!)
In 2023, Skean, Ehrenborg, and Jaromczyk showed that equation
\[ \lfloor 4.0816 \cdot 8.5714^\frac{k}{2.2449} \rfloor \]
generates the sequence 1, 4, 10, 27, 72, 187, 488, ..., which has worst-case runtime of \(O(N^\frac{3}{2})\).
In other words, there is still more work to be done!
Example of simple idea leading to substantial performance gains
Useful in practice
Simple algorithm, nontrivial performance, interesting questions
Lesson: Some good algorithms are still awaiting discovery
This section: Elementary sorting algorithms
Order of growth of running time to sort an array of \(N\) items
| algorithm | best | average | worst |
|---|---|---|---|
| selection sort | \(N^2\) | \(N^2\) | \(N^2\) |
| insertion sort | \(N\) | \(N^2\) | \(N^2\) |
| Shellsort (\(3x+1\)) | \(N \lg N\) | ? | \(N^\threehalves\) |
| goal | \(N\) | \(N \lg N\) | \(N \lg N\) |
Next section: \(N \lg N\) sorting algorithms (in worst case)
Goal: Rearrange array so that result is a uniformly random permutation (uniformly → all permutations are equally likely)



Proposition: Shuffle sort produces a uniformly random permutation, assuming real numbers uniformly at random (and no ties)
Microsoft antitrust probe by EU: Microsoft agreed to provide a randomized ballot screen for users to select browser in Windows 7.

However, IE8 appeared last 50% of the time!
Microsoft antitrust probe by EU: Microsoft agreed to provide a randomized ballot screen for users to select browser in Windows 7.
Solution? Implement shuffle sort by making comparator always return a random answer
// browser comparator (should implement a total order!)
public int compareTo(Browser that) {
double r = Math.random();
if(r < 0.5) return -1;
if(r > 0.5) return +1;
return 0;
}
i, pick integer r between 0 and i uniformly at randoma[i] and a[r]
i, pick integer r between 0 and i uniformly at randoma[i] and a[r]i, pick integer r between 0 and i uniformly at randoma[i] and a[r]Proposition [Fisher-Yates 1938]: Knuth shuffling algorithm produces a uniformly random permutation of the input array in linear time, assuming integers uniformly at random.
i, pick integer r between 0 and i uniformly at randoma[i] and a[r]Common bug: picking r between 0 and N-1.
Correct variant: between i and N-1
public class StdRandom {
/* ... */
public static void shuffle(Object[] a) {
int N = a.length;
for(int i = 0; i < N; i++) {
int r = StdRandom.uniform(i+1); // between 0 and i
exch(a, i, r);
}
}
}
Q. What happens if integer is chosen between 0 and N-1?
Probability of each result when shuffling A B C
| permutation | Knuth shuffle | broken shuffle |
|---|---|---|
A B C |
\(1/6\) | \(4/27\) |
A C B |
\(1/6\) | \(5/27\) |
B A C |
\(1/6\) | \(5/27\) |
B C A |
\(1/6\) | \(5/27\) |
C A B |
\(1/6\) | \(4/27\) |
C B A |
\(1/6\) | \(4/27\) |
Texas hold'em poker: Software must shuffle electronic cards

// shuffling algorithm in FAQ at www.planetpoker.com
for i := 1 to 52 do begin
r := random(51) + 1; // between 1 and 51
swap := card[r];
card[r] := card[i];
card[i] := swap;
end;
Bug 1: Random number r never 52 ⇒ 52nd card cannot end up in 52nd place
Bug 2: Shuffle not uniform (should be between 1 and i)
Bug 3: random() uses 32-bit seed ⇒ \(2^{32}\) possible shuffles
Bug 4: Seed = milliseconds since midnight ⇒ 86.4 million shuffles
“The generation of random numbers is too important to be left to chance.
”
—Robert R. Coveyou
Best practices for shuffling (if your business depends on it)
![]() |
![]() |
![]() |
Bottom line: Shuffling a deck of cards is hard!

Lavarand was a Silicon Graphics service that used a wall of lava lamps to generate random numbers.
As of 2017, Cloudfare maintains a similar system of lava lamps for securing approximately 10% of the Internet's traffic (wikipedia, Tom Scott: The Lava Lamps That Help Keep The Internet Secure)