12 Sorting
12 Sorting
Riley Porter
2 4 5 3 8 7 1 6 2 4 5 3 8 7 1 6
3 4
shift other elements over and already new current item
sorted section is now larger
2 3 4 5 8 7 1 6 2 3 4 5 8 7 1 6
• Runtime?
Best-case _____ Worst-case _____ Average-case ____
• Loop invariant: when loop index is i, first i elements are sorted from
the first i elements in the array
• Runtime?
Best-case O(n) Worst-case O(n2) Average-case O(n2)
start sorted start reverse sorted (see text)
1 2
current index next smallest current index next smallest
1 2 3 7 8 6 4 5 1 2 3 7 8 6 4 5
3 4
next index next smallest
now ‘already sorted’ section is one larger
1 2 3 4 8 6 7 5 1 2 3 4 8 6 7 5
• Loop invariant: when loop index is i, first i elements are sorted and i
smallest elements in the array
• Runtime?
Best-case _____ Worst-case _____ Average-case ____
• Runtime?
Best-case, Worst-case, and Average-case O(n2)
algorithm(input) {
if (small enough) {
CONQUER, solve, and return input
} else {
DIVIDE input into multiple pieces
RECURSE on each piece
COMBINE and return results
}
}
CSE373: Data Structures &
22
Algorithms
Divide-and-Conquer Sorting
Two great sorting methods are fundamentally divide-and-conquer
Mergesort:
Sort the left half of the elements (recursively)
Sort the right half of the elements (recursively)
Merge the two sorted halves into a sorted whole
Quicksort:
Pick a “pivot” element
Divide elements into less-than pivot and greater-than pivot
Sort the two divisions (recursively on each)
Answer is: sorted-less-than....pivot....sorted-greater-than
Unsorted
Unsorted Unsorted
Sorted
CSE373: Data Structures &
24
Algorithms
Merge Sort: Pseudocode
Core idea: split array in half, sort each half, merge back
together. If the array has size 0 or 1, just return it
unchanged
mergesort(input) {
if (input.length < 2) {
return input;
} else {
smallerHalf = sort(input[0, ..., mid]);
largerHalf = sort(input[mid + 1, ...]);
return merge(smallerHalf, largerHalf);
}
}
7 2 8 4 5 3 1 6
7 2 8 4 5 3 1 6
7 2 8 4 5 3 1 6
2 4 7 8 1 3 5 6
2 7 4 8 3 5 1 6
7 2 8 4 5 3 1 6
Result:
Result: 1
Result: 1 2
Result: 1 2 3
Result: 1 2 3 4
Result: 1 2 3 4 5
Result: 1 2 3 4 5 6
Result: 1 2 3 4 5 6 7
Result: 1 2 3 4 5 6 7 8
O(log(n))
levels
5 2 8 4 7 3 1 6
5
2 4 7 8
pivot
1 3 6
Unsorted
<= P P >P
Sorted
CSE373: Data Structures &
40
Algorithms
Quick Sort Pseudocode
Core idea: Pick some item from the array and call it the pivot. Put all
items smaller in the pivot into one group and all items larger in the
other and recursively sort. If the array has size 0 or 1, just return it
unchanged.
quicksort(input) {
if (input.length < 2) {
return input;
} else {
pivot = getPivot(input);
smallerHalf = sort(getSmaller(pivot, input));
largerHalf = sort(getBigger(pivot, input));
return smallerHalf + pivot + largerHalf;
}
}
S1 S2 partition S
0 31 75
13 43 65
92 81
26 57
Quicksort(S1) and
S1 S2 Quicksort(S2)
0 13 26 31 43 57 65 75 81 92
S 0 13 26 31 43 57 65 75 81 92 Presto! S is sorted
[Weiss]
Conquer
1 2 3 4 5 6 8 9
8 2 9 4 5 3 1 6
• Worst pivot?
1
– Greatest/least element 8 2 9 4 5 3 6
– Problem of size n - 1
– O(n2)
0 1 2 3 4 5 6 7 8 9
6 1 4 9 0 3 5 2 7 8
Move fingers 6 1 4 9 0 3 5 2 7 8
Swap 6 1 4 2 0 3 5 9 7 8
Move fingers
6 1 4 2 0 3 5 9 7 8
Move pivot
5 1 4 2 0 3 6 9 7 8
CSE373: Data Structures &
49
Algorithms
Analysis
• Best-case: Pivot is always the median
T(0)=T(1)=1
T(n)=2T(n/2) + n -- linear-time partition
Same recurrence as mergesort: O(n log n)
(𝑛−1)! 𝑛
– 𝑇 𝑛 =𝑛+ 𝑖=1 𝑇 𝑖 − 1 + 𝑇(𝑛 − 𝑖)
𝑛!
actual order
CSE373: Data Structures &
56
Algorithms
What the Decision Tree Tells Us
• A binary tree because each comparison has 2 outcomes
(we’re comparing 2 elements at a time)
• Because any data is possible, any algorithm needs to ask
enough questions to produce all orderings.
Example, n=3
a[0]<a[1]<a[2] a[0]<a[2]<a[1] a[1]<a[0]<a[2]
a[1]<a[2]<a[0] a[2]<a[0]<a[1] a[2]<a[1]<a[0]
In general, n choices for least element, n-1 for next, n-2 for next, …
– n(n-1)(n-2)…(2)(1) = n! possible orderings
That means with n! possible leaves, best height for tree is log(n!),
given that best case tree splits leaves in half at each branch
CSE373: Data Structures &
58
Algorithms
What does that mean for runtime?
That proves runtime is at least (log (n!)). Can we write that more clearly?
4 2
5 3
CSE373: Data Structures & Algorithms 61
Analyzing Bucket Sort
• Overall: O(n+K)
– Linear in n, but also linear in K
• Idea:
– Bucket sort on one digit at a time
• Number of buckets = radix
• Starting with least significant digit
• Keeping sort stable
– Do one pass per digit
– Invariant: After k passes (digits), the last k digits are sorted
3 passes (input is 3 digits at max), on each pass, stable sort the input highlighted in yellow
Input: 478
Order now: 721
537 First pass:
9 003
bucket sort by ones digit
721 143
3 537
38 067
143 478
67 038
009
CSE373: Data Structures &
66
Algorithms
0 1 2 3 4 5 6 7 8 9
Example 721 3
143
537 478
67 38
9
Radix = 10
0 1 2 3 4 5 6 7 8 9
3 721 537 143 67 478
9 38
Example 3
9
721 537 143
38
67 478
Radix = 10
0 1 2 3 4 5 6 7 8 9
3 143 478 537 721
9
38
Order was: 003 67 Order now: 003
009
009
721 Third pass: 038
537 stable bucket sort by 100s digit 067
038
143
143
478
067
537
478
721 &
CSE373: Data Structures
68
Algorithms
Analysis
Input size: n
Number of buckets = Radix: B
Number of passes = “Digits”: P
Work per pass is 1 bucket sort: O(B+n)
Total work is O(P(B+n))
Compared to comparison sorts, sometimes a win, but
often not
– Example: Strings of English letters up to length 15
• Run-time proportional to: 15*(52 + n)
• This is less than n log n only if n > 33,000
• Of course, cross-over point depends on constant factors of the
implementations
CSE373: Data Structures &
69
Algorithms
Sorting Takeaways
• Simple O(n2) sorts can be fastest for small n
– Selection sort, Insertion sort (latter linear for mostly-sorted)
– Good for “below a cut-off” to help divide-and-conquer sorts
• O(n log n) sorts
– Heap sort, in-place but not stable nor parallelizable
– Merge sort, not in place but stable and works as external sort
– Quick sort, in place but not stable and O(n2) in worst-case
• Often fastest, but depends on costs of comparisons/copies
• (n log n) is worst-case and average lower-bound for
sorting by comparisons
• Non-comparison sorts
– Bucket sort good for small number of possible key values
– Radix sort uses fewer buckets and more phases
• Best way to sort? It depends!
CSE373: Data Structures &
70
Algorithms