04 Mergesort
04 Mergesort
M ERGESORT
‣ mergesort
‣ bottom-up mergesort
‣ sorting complexity
‣ comparators
‣ stability
...
...
2
M ERGESORT
‣ mergesort
‣ bottom-up mergesort
‣ sorting complexity
‣ comparators
‣ stability
Mergesort
Basic plan.
・Divide array into two halves.
・Recursively sort each half.
・Merge two halves.
4
Abstract in-place merge demo
Goal. Given two sorted subarrays a[lo] to a[mid] and a[mid+1] to a[hi], replace with sorted subarray a[lo] to a[hi].
Goal. Given two sorted subarrays a[lo] to a[mid] and a[mid+1] to a[hi],
replace with sorted subarray a[lo] to a[hi].
lo mid mid+1 hi
a[] E E G M R A C E R T
sorted sorted
lo hi
a[] A C E E E G M R R T
sorted
5
Merging
Q. Use
A. Howan
toauxiliary
combinearray.
two sorted subarrays into a sorted whole.
6
Merging: C++ implementation
template<typename T>
void merge(vector<T>& a, vector<T>& aux, int lo, int mid, int hi) {
lo i mid j hi
aux[] A G L O R H I M S T
k
a[] A G H I L M
7
Mergesort: C++ implementation
void merge(vector<T>& a, vector<T>& aux, int lo, int mid, int hi)
{ /* as before */ }
void sort(vector<T>& a, vector<T>& aux, int lo, int hi) {
if (hi <= lo) return;
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid+1, hi);
merge(a, aux, lo, mid, hi);
}
void sort(vector<T>& a) {
int N = std::size(a);
vector<T> aux(N);
sort(a, aux, 0, N - 1);
}
lo mid hi
10 11 12 13 14 15 16 17 18 19
8
Mergesort: trace
9
Mergesort: animation
50 random items
algorithm position
in order
current subarray
not in order
http://www.sorting-algorithms.com/merge-sort
10
Mergesort: animation
50 reverse-sorted items
algorithm position
in order
current subarray
not in order
http://www.sorting-algorithms.com/merge-sort
11
Mergesort: empirical analysis
13
Divide-and-conquer recurrence: proof by picture
Pf 1. [assuming N is a power of 2]
𝐷 (𝑁) 𝑁 = 𝑁
𝐷 (𝑁 / 2) 𝐷 (𝑁 / 2) 2 (𝑁/2) = 𝑁
lg 𝑁
𝐷(𝑁/4) 𝐷(𝑁/4) 𝐷(𝑁/4) 𝐷(𝑁/4) 4 (𝑁/4) = 𝑁
⋮ 𝑇(𝑁) = 𝑁 lg 𝑁
14
Divide-and-conquer recurrence: proof by induction
Pf 2. [assuming N is a power of 2]
・Base case: 𝑁 = 1.
・Inductive hypothesis: 𝐷 (𝑁) = 𝑁 lg 𝑁.
・Goal: show that 𝐷 (2𝑁) = (2𝑁) lg(2𝑁).
= 2 𝑁 lg 𝑁 + 2𝑁 inductive hypothesis
= 2 𝑁 (lg(2𝑁) – 1) + 2𝑁 algebra
= 2 𝑁 lg(2𝑁) QED
15
Mergesort: number of array accesses
Key point. Any algorithm with the following structure takes 𝑁 log 𝑁 time:
void linearithmic(int N)
{
if (N == 0) return;
linearithmic(N/2); solve two problems
linearithmic(N/2); of half the size
A C D G H I M N U B E F J O P Q R S T
V
A B C D E F G H I J M N O P Q R S T U V
merged result
18
Mergesort with cutoff to insertion sort: visualization
19
Mergesort: practical improvements
A B C D E F G H I J M N O P Q R S T U V
A B C D E F G H I J M N O P Q R S T U V
20
Mergesort: practical improvements
Eliminate the copy to the auxiliary array. Save time (but not space)
by switching the role of the input and auxiliary array in each recursive call.
void merge(vector<T>& a, vector<T>& aux, int lo, int mid, int hi) {
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) aux[k] = a[j++];
else if (j > hi) aux[k] = a[i++];
merge from a[] to aux[]
else if (a[j] < a[i]) aux[k] = a[j++];
else aux[k] = a[i++];
}}
void sort(vector<T>& a, vector<T>& aux, int lo, int hi) {
if (hi <= lo) return; assumes aux[] is initialize to a[] once,
Basic plan.
・Pass through array, merging subarrays of size 1.
・Repeat for subarrays of size 2, 4, 8, ....
23
Bottom-up mergesort: Java implementation
void mergesort_bu(vector<T>& a) {
int N = std::size(a);
vector<T> aux(N);
for (int sz = 1; sz < N; sz = sz+sz)
for (int lo = 0; lo < N-sz; lo += sz+sz)
merge(a, aux, lo, lo+sz-1, std::min(lo+sz+sz-1, N-1));
}
input
1 5 10 16 3 4 23 9 13 2 7 8 12 14
first run
1 5 10 16 3 4 23 9 13 2 7 8 12 14
second run
1 5 10 16 3 4 23 9 13 2 7 8 12 14
1 3 4 5 10 16 23 9 13 2 7 8 12 14
Tradeoff. Fewer passes vs. extra compares per pass to identify runs.
26
Timsort
・Natural mergesort.
・Use binary insertion sort to make initial runs (if needed).
・A few more clever optimizations.
Tim Peters
Intro
-----
This describes an adaptive, stable, natural mergesort, modestly called
timsort (hey, I earned it <wink>). It has supernatural performance on many
kinds of partially ordered arrays (less than lg(N!) comparisons needed, and
as few as N-1), yet as fast as Python's previous highly tuned samplesort
hybrid on random arrays.
In a nutshell, the main routine marches over the array once, left to right,
alternately identifying the next run, then merging it into the previous
runs "intelligently". Everything else is complication for speed, and some
hard-won measure of memory efficiency.
...
http://www.python.org/dev/peps/pep-0020/
28
M ERGESORT
‣ mergesort
‣ bottom-up mergesort
‣ sorting complexity
‣ comparators
‣ stability
Complexity of sorting
Example: sorting.
・Model of computation: decision tree. can access information
only through compares
・Cost model: compares. (e.g., Java Comparable framework)
・Upper bound: ~ N lg N from mergesort.
・Lower bound:
・Optimal algorithm:
30
Decision tree (for 3 distinct keys a, b, and c)
a<b
height of tree =
yes no worst-case number
code between compares of compares
(e.g., sequence of exchanges)
b<c a<c
yes no yes no
yes no yes no
Pf.
・Assume array consists of N distinct values a through a .
1 N
32
Compare-based lower bound for sorting
Pf.
・Assume array consists of 𝑁 distinct values 𝑎1 through 𝑎𝑁 .
・Worst case dictated by height ℎ of decision tree.
・Binary tree of height ℎ has at most 2 leaves.ℎ
2ℎ ≥ # leaves ≥ 𝑁!
⇒ ℎ ≥ lg( 𝑁! ) ~ 𝑁 lg 𝑁
Stirling's formula
33
Complexity of sorting
Example: sorting.
・Model of computation: decision tree.
・Cost model: compares.
・Upper bound: ~ 𝑁 lg 𝑁 from mergesort.
・Lower bound: ~ 𝑁 lg 𝑁.
・Optimal algorithm = mergesort.
34
Complexity results in context
Lower bound may not hold if the algorithm can take advantage of:
36
M ERGESORT
‣ mergesort
‣ bottom-up mergesort
‣ sorting complexity
‣ comparators
‣ stability
Sort countries by gold medals
38
Sort countries by total medals
39
Sort music library by artist
40
Sort music library by song name
41
Operator overloading: review
class Date {
private:
const int month, day, year;
public:
Date(int m, int d, int y) : month {m}, day {d}, year {y} { }
44
Custom comparators
reverse natural
time the is Now
order
Bottom line. Decouples the definition of the data type from the
definition of what it means to compare two objects of that type.
46
Custom comparators: using with our sorting libraries
47
Custom comparators: implementation
48
M ERGESORT
‣ mergesort
‣ bottom-up mergesort
‣ sorting complexity
‣ comparators
‣ stability
Stability
A stable sort preserves the relative order of items with equal keys.
50
Stability
51
Stability: insertion sort
template<typename T>
void insertion_sort(vector<T>& a) {
int N = std::size(a);
for (int i = 0; i < N; i++)
for (int j = i; j > 0 && (a[j] < a[j-1]); j--)
std::swap(a[j], a[j-1]);
i j 0 1 2 3 4
}
0 0 B1 A1 A2 A3 B2
1 0 A1 B1 A2 A3 B2
2 1 A1 A2 B1 A3 B2
3 2 A1 A2 A3 B1 B2
4 4 A1 A2 A3 B1 B2
A1 A2 A3 B1 B2
template<typename T>
void selection_sort(vector<T>& a) {
int N = std::size(a);
for (int i = 0; i < N; i++) {
int min = i; i min 0 1 2
0 2 B1 B2 A
for (int j = i+1; j < N; j++)
1 1 A B2 B1
if (a[j] < a[min])
2 2 A B2 B1
min = j;
A B2 B1
std::swap(a[i], a[min]);
}
}
} 1 A1 B2 B3 B4 B1
A1 B2 B3 B4 B1
Pf by counterexample. Long-distance exchanges.
54
Stability: mergesort
void merge(...) {
for (int k = lo; k <= hi; k++)
aux[k] = a[k];
int i = lo, j = mid+1;
for (int k = lo; k <= hi; k++) {
if (i > mid) a[k] = aux[j++];
else if (j > hi) a[k] = aux[i++];
else if (aux[j] < aux[i]) a[k] = aux[j++];
else a[k] = aux[i++];
}
0 1 2 3 4 5 6 7 8 9 10
}
A1 A2 A3 B D A4 A5 C E F G
57