Lecture2 Compressed
Lecture2 Compressed
Technical content
• Karatsuba integer multiplication
• Example of “Divide and Conquer”
• Not-so-rigorous analysis Ollie the Siggi the
over-achieving studious
ostrich stork
Today
• Things we want to know about algorithms:
• Does it work?
• Is it efficient?
6 4 3 8 1 5 2 7
1 2 3 4 5 6 7 8
I hope everyone did the
pre-lecture exercise!
def mysteryAlgorithmOne(A):
B = [None for i in range(len(A))]
for i in range(len(B)):
What was the if B[i] == None or B[i] > x:
mystery sort j = len(B)-1
while j > i:
algorithm? B[j] = B[j-1]
j -= 1
B[i] = x
break
1. MergeSort return B
def InsertionSort(A):
for i in range(1,len(A)):
current = A[i]
j = i-1
while j >= 0 and A[j] > current:
A[j+1] = A[j]
j -= 1
A[j+1] = current
InsertionSort 6 4 3 8 5
example
Start by moving A[1] toward
the beginning of the list until
you find something smaller
(or can’t go any further): Then move A[3]:
6 4 3 8 5 3 4 6 8 5
4 6 3 8 5 3 4 6 8 5
Then move A[2]: Then move A[4]:
4 6 3 8 5 3 4 6 8 5
3 4 6 8 5 3 4 5 6 8
Then we are done!
Insertion Sort
1. Does it work?
2. Is it fast?
Empirical answers…
• Does it work?
• You saw it worked on the pre-Lecture exercise.
• Is it fast?
• IPython notebook lecture2_sorting.ipynb says:
Insertion Sort
1. Does it work?
2. Is it fast?
• Proceed by induction.
• Inductive Hypothesis:
• The loop invariant(i) holds at the end of the ith iteration (of the outer
loop).
• Base case (i=0):
• Before the algorithm starts, A[:1] is sorted. ✓
• Inductive step:
• Conclusion:
• At the end of the n-1’st iteration (aka, at the end of the algorithm),
A[:n] = A is sorted.
• That’s what we wanted!✓
Can we do better?
The plan
• Part I: Sorting Algorithms
• InsertionSort: does it work and is it fast?
• MergeSort: does it work and is it fast?
• Skills:
• Analyzing correctness of iterative and recursive algorithms.
• Analyzing running time of recursive algorithms (part A)
Divide and
Conquer: Big problem
Smaller Smaller
problem problem
Recurse! Recurse!
6 4 3 8 1 5 2 7
Recursive magic! Recursive magic!
3 4 6 8 1 2 5 7
How would
you do this
MERGE! 1 2 3 4 5 6 7 8 in-place?
MergeSort Pseudocode
MERGESORT(A):
• n = length(A)
• if n ≤ 1: If A has length 1,
It is already sorted!
• return A
Sort the left half
• L = MERGESORT(A[ 0 : n/2])
Sort the right half
• R = MERGESORT(A[n/2 : n ])
• return MERGE(L,R) Merge the two halves
What actually happens?
First, recursively break up the array all the way down to the
base cases
6 4 3 8 1 5 2 7
6 4 3 8 1 5 2 7
6 4 3 8 1 5 2 7
6 4 3 8 1 5 2 7
This array of
length 1 is
sorted!
Then, merge them all back up!
Sorted sequence!
1 2 3 4 5 6 7 8
Merge!
3 4 6 8 1 2 5 7
Merge! Merge!
4 6 3 8 1 5 2 7
Merge! Merge! Merge! Merge!
6 4 3 8 1 5 2 7
A bunch of sorted lists of length 1 (in the order of the original sequence).
Two questions
Empirically:
1. Seems to.
2. Maybe?
Again we’ll use induction.
It works Let’s assume n = 2t This time with an invariant
that will remain true after
every recursive call.
• Inductive hypothesis:
“In every recursive call,
MERGESORT returns a sorted array.”
Empirically
This
grows
like n2
This supposedly
grows like nlog(n)
The constant doesn’t matter:
eventually, 𝑛2 > 111111 ⋅ 𝑛 log(𝑛)
All logarithms in this
Quick log refresher course are base 2
32 64 log(128) = 7
16 32 log(256) = 8
16 log(512) = 9
8 .
8
4 4 .
2 .
2 log(number of particles in
1 1 the universe) < 280
log(32) = 5 log(64) = 6
It’s fast!
CLAIM:
(Size 1)
How much work in this sub-problem?
+
Time spent within the
n/2t+1 n/2t+1 two sub-problems
How much work in this sub-problem?
Let k=n/2t…
+
Time spent within the
k/2 k/2 two sub-problems
Code for the MERGE
How long does it k step is given in the
Lecture2 notebook.
take to MERGE? k/2 k/2
k/2 k/2
3 4 6 8 1 2 5 7
MERGE! 1 2 3 4 5 6 7 8
k
Code for the MERGE
How long does it k step is given in the
Lecture2 notebook.
take to MERGE? k/2 k/2
• Time to initialize an
array of size k
• Plus the time to
initialize three counters
• Plus the time to
increment two of those Let’s say no more
counters k/2 times
each than 11k operations.
• Plus the time to
compare two values at
There’s some
least k times
justification for this
• Plus the time to copy k
number “11” in the
values from the
lecture notes, but it’s
existing array to the big
really pretty arbitrary.
array.
• Plus…
Plucky the Lucky the
Pedantic Penguin lackadaisical lemur
Recursion tree #
Size of
each
Amount of work
Level problems at this level
problem
Size n 11n
0 1 n
n/2 n/2
1 2 n/2 11n
n/4 n/4 n/4 n/4 2 4 n/4 11n
… …
n/2t n/2t n/2t n/2t n/2t
n/2t t 2t n/2t 11n
… …
log(n) n 1 11n
(Size 1)
Total runtime…
• log(n) + 1 levels
1 2 3 4 5 6 7 8
should take zero steps…
12345678
• In this class, we will focus on worst-case analysis
Here is my algorithm!
Here is an
Algorithm: input!
Do the thing
Do the stuff
Return the answer
Algorithm
designer
Pros: Cons:
• Abstracts away from • Only makes sense if n is
hardware- and language- large (compared to the
specific issues. constant factors).
• Makes algorithm analysis 2100000000000000 n
much more tractable. is “better” than n2 ?!?!
pronounced “big-oh of …” or sometimes “oh of …”
• Formally,
𝑇 𝑛 =𝑂 𝑔 𝑛
⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
0 ≤ 𝑇 𝑛 ≤ 𝑐 ⋅ 𝑔(𝑛)
𝑇 𝑛 =𝑂 𝑔 𝑛
Example ⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
2𝑛< + 10 = 𝑂 𝑛< 0 ≤ 𝑇 𝑛 ≤ 𝑐 ⋅ 𝑔(𝑛)
3n2
2n2 + 10
n2
𝑇 𝑛 =𝑂 𝑔 𝑛
Example ⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
2𝑛< + 10 = 𝑂 𝑛< 0 ≤ 𝑇 𝑛 ≤ 𝑐 ⋅ 𝑔(𝑛)
Formally:
3n2 • Choose c = 3
• Choose n0 = 4
• Then:
∀𝑛 ≥ 4,
0 ≤ 2𝑛< + 10 ≤ 3 ⋅ 𝑛<
n2
𝑇 𝑛 =𝑂 𝑔 𝑛
same Example ⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
2𝑛< + 10 = 𝑂 𝑛< 0 ≤ 𝑇 𝑛 ≤ 𝑐 ⋅ 𝑔(𝑛)
Formally:
7n2 • Choose c = 7
• Choose n0 = 2
• Then:
∀𝑛 ≥ 2,
0 ≤ 2𝑛< + 10 ≤ 7 ⋅ 𝑛<
n2
𝑇 𝑛 =𝑂 𝑔 𝑛
Another example: ⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
𝑛 = 𝑂(𝑛 )2 0 ≤ 𝑇 𝑛 ≤ 𝑐 ⋅ 𝑔(𝑛)
g(n) = n2 • Choose c = 1
• Choose n0 = 1
• Then
∀𝑛 ≥ 1,
T(n) = n 0 ≤ 𝑛 ≤ 𝑛<
Ω(…) means a lower bound
• We say “T(n) is Ω(g(n))” if g(n) grows at most as fast
as T(n) as n gets large.
• Formally,
𝑇 𝑛 =Ω 𝑔 𝑛
⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
0≤𝑐⋅𝑔 𝑛 ≤𝑇 𝑛
Switched these!!
𝑇 𝑛 =Ω 𝑔 𝑛
Example ⟺
∃𝑐, 𝑛5 > 0 𝑠. 𝑡. ∀𝑛 ≥ 𝑛5 ,
• Choose c = 1/3
• Choose n0 = 3
• Then
∀𝑛 ≥ 3,
3𝑛
0≤ ≤ 𝑛 log < 𝑛
3
Θ(…) means both!
• We say “T(n) is Θ(g(n))” if:
T(n) = O(g(n))
-AND-
T(n) = Ω(g(n))
Some more examples
• All degree k polynomials* are O(nk)
• For any k ≥ 1, nk is not O(nk-1)
• 3n is NOT O(2n)
• log(n) = Ω(ln(n))
• log(n) = Θ( 2loglog(n) )
Asymptotic Notation
• This makes both Plucky and Lucky happy.
• Plucky the Pedantic Penguin is happy because
there is a precise definition.
• Lucky the Lackadaisical Lemur is happy because we
don’t have to pay close attention to all those pesky
constant factors like “11”.
Wrap-Up
Recap
• InsertionSort runs in time O(n2)
• MergeSort is a divide-and-conquer algorithm that
runs in time O(n log(n))