```
insertion_sort(A, n):
for j = 2 to n:
key = A[j]
i = j - 1
while i > 0 and A[i] > key:
A[i+1] = A[i]
i = i - 1
A[i+1] = key
```
| In: | *E* | **B** | D | F | A | C |
|-----|-------|-------|-------|-------|-------|-------|
| j=3 | B | *E* | **D** | F | A | C |
| j=4 | B | D | *E* | **F** | A | C |
| j=5 | *B* | *D* | *E* | *F* | **A** | C |
| j=6 | A | B | *D* | *E* | *F* | **C** |
| Out:| A | B | C | D | E | F |
>>>
Not the **fastest** solution, but pretty **easy** to code
---
## Proof of correctness
+ Loop **invariant**:
+ Property that is true **before**, **during**, and **after** loop
+ For insertion sort: at each iteration of loop,
+ part of array `A[1 .. j-1]` is in **sorted** order
```
insertion_sort(A, n):
for j = 2 to n:
key = A[j]
i = j - 1
while i > 0 and A[i] > key:
A[i+1] = A[i]
i = i - 1
A[i+1] = key
```
---
## Complexity analysis
Let \`t_j\` be the number of times the loop condition is checked
in the inner "while" loop:
```
insertion_sort(A, n):
for j = 2 to n: # c0 * n
key = A[j] # c1 * (n-1)
i = j - 1 # c2 * (n-1)
while i > 0 and A[i] > key: # c3 * sum (t_j)
A[i+1] = A[i] # c4 * sum (t_j - 1)
i = i - 1 # c5 * sum (t_j - 1)
A[i+1] = key # c6 * (n-1)
```
Summation notation: \`sum_2^n t_j = t_2 + t_3 + ... + t_n\`
---
## Best vs. worst case
+ **Best** case is if input is **pre-sorted**:
+ Still need to **scan** to verify sorted,
+ But inner **while** loop only has 1 iteration: \`t_j=1\`
+ Total complexity: T(n) = a n + b, for some a, b
+ **Linear** in n
+ **Worst** case: input is in **reverse** order!
+ Inner "while" loop always max iterations: \`t_j=j\`
+ Calculate **total** complexity T(n):
+ Pick a line in inner loop, e.g., **line 5**: `A[i+1] = A[i]`
+ Complexity of other lines **similar**
---
## Worst case complexity
+ **Total** complexity for line 5, worst-case:
\` c_4 sum_2^n(t_j-1) = c_4 sum_2^n(j-1) \`
\` = c_4 (n-1)n/2 = (c_4/2)n^2 - (c_4/2)n \`
+ **Quadratic** in n
+ **Average** case: input is random, \`t_j=j/2\` on average
+ Still quadratic (only changes by a **constant** factor)
---
## Theta (Θ) notation
+ Insertion sort, line 5: \` (c_4 / 2) n^2 - (c_4/2)n \`
+ **Constants** \`c_1, c_2, ...\` may vary for different computers
+ As n gets **big**, constants become **irrelevant**
+ Even the n term is dominated by the \`n^2\` term
+ Complexity of insertion sort is on **order** of \`n^2\`
+ Notation: \`T(n) = Theta(n^2)\` ("theta")
+ \`Theta(1)\` means an algorithm runs in **constant time**
+ i.e., does not depend on **size** of input
+ We'll define Θ more **precisely** later today
---
## Outline for today
+ Algorithmic analysis
+ Insertion sort
+ **Discrete math review**
+ **Logic and proofs**
+ Monotonicity, limits, iterated functions
+ Fibonacci sequence and golden ratio
+ Asymptotic notation: Θ, O, Ω, o, ω
+ Proving asymptotic bounds
---
## Logic notation
+ \`not A\` (or !A): "**not** A"
+ e.g., let A = "*it is Tue*": then \`not A\` = "*it is not Tue*"
+ A ⇒ B: "**implies**", "if A, then B"
+ e.g., let B = "*meatloaf*":
+ then A ⇒ B = "*if Tue, then meatloaf*"
+ A ⇔ B: if and only if ("**iff**"):
+ **equivalence**: (A ⇒ B) and (B ⇒ A)
+ **John 14:15**: "*If you love me, keep my commands*"
+ **v21**: "*Whoever keeps my commands loves me*"
+ **v24**: "*He who does not love me will not obey my teaching*"
---
## Logic notation: ∀ and ∃
+ ∀: "**for all**",
+ e.g., "∀ day: meal(day) = meatloaf"
+ "*For all days, the meal on that day is meatloaf*"
+ ∃: "there **exists**" (not necessarily unique)
+ e.g., "∃ day: meal(day) = meatloaf"
+ "*There exists a day on which the meal is meatloaf*"
---
## Logic: contrapos and converse
+ **Contrapositive** of "A ⇒ B" is \`not B => not A\`
+ **Equivalent** to original statement
+ "*If Tue, then meatloaf*" ⇔