0% found this document useful (0 votes)
18 views34 pages

Lecture 3 1

The document discusses algorithms and their asymptotic complexity. It defines big O, Omega and Theta notation and provides examples of calculating time complexity for linear search and insertion sort algorithms. The complexity of linear search is O(n) and insertion sort is O(n^2) in the worst case.

Uploaded by

hallertjohn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views34 pages

Lecture 3 1

The document discusses algorithms and their asymptotic complexity. It defines big O, Omega and Theta notation and provides examples of calculating time complexity for linear search and insertion sort algorithms. The complexity of linear search is O(n) and insertion sort is O(n^2) in the worst case.

Uploaded by

hallertjohn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Algorithms – Rosen Section 3.1-3.

Anna-Simone Frank1

MNF130

Spring 2024

1
Slides created by Tom Michoel and modified by Erik Maartensson and
Anna-Simone Frank
Algorithms

An algorithm is a finite sequence of precise instructions for performing a


computation or solving a problem.

Importance in discrete math course:


I Prove that a proposed algorithm solves the given problem.
I Compute the complexity of an algorithm.
I Many applications of discrete math cannot be discussed without
computational considerations (e.g. cryptography).

We describe algorithms using pseudocode instead of in a specific


programming language.
Asymptotic complexity

Given an algorithm that solves some problem in f (n) operations when the
problem size is n.
I How do we compare this algorithm against other algorithms solving
the same problem?
I How do we compare the algorithm against itself for other problem
sizes.
Asymptotic complexity

Given an algorithm that solves some problem in f (n) operations when the
problem size is n.
I How do we compare this algorithm against other algorithms solving
the same problem?
I How do we compare the algorithm against itself for other problem
sizes.

I The result of implementing the algorithm and testing it will depend


highly on our available hardware and the efficiency of our
implementation.
I Calculating the exact number of operations needed is tedious and
might not give a good picture of how this changes with the problem
size.
Asymptotic complexity

Given an algorithm that solves some problem in f (n) operations when the
problem size is n.
I How do we compare this algorithm against other algorithms solving
the same problem?
I How do we compare the algorithm against itself for other problem
sizes.

I The result of implementing the algorithm and testing it will depend


highly on our available hardware and the efficiency of our
implementation.
I Calculating the exact number of operations needed is tedious and
might not give a good picture of how this changes with the problem
size.
We use perhaps the most beautiful concept in computer science -
asymptotic time complexity!
Definitions of asymptotic complexity
Let f (n) denote the number of operations needed for an algorithm to
solve a problem of size n. We use the following asymptotic notation. The
first definition is the most frequently used one.
Definitions of asymptotic complexity
Let f (n) denote the number of operations needed for an algorithm to
solve a problem of size n. We use the following asymptotic notation. The
first definition is the most frequently used one.
Definition (Asymptotic upper bound)
We say that f (n) is O(g (n)) if there is a constant C such that
f (n) ≤ C · g (n) for all sufficiently large n.
Definitions of asymptotic complexity
Let f (n) denote the number of operations needed for an algorithm to
solve a problem of size n. We use the following asymptotic notation. The
first definition is the most frequently used one.
Definition (Asymptotic upper bound)
We say that f (n) is O(g (n)) if there is a constant C such that
f (n) ≤ C · g (n) for all sufficiently large n.
Definition (Asymptotic lower bound)
We say that f (n) is Ω(g (n)) if there is a constant C such that
f (n) ≥ C · g (n) for all sufficiently large n.
Definitions of asymptotic complexity
Let f (n) denote the number of operations needed for an algorithm to
solve a problem of size n. We use the following asymptotic notation. The
first definition is the most frequently used one.
Definition (Asymptotic upper bound)
We say that f (n) is O(g (n)) if there is a constant C such that
f (n) ≤ C · g (n) for all sufficiently large n.
Definition (Asymptotic lower bound)
We say that f (n) is Ω(g (n)) if there is a constant C such that
f (n) ≥ C · g (n) for all sufficiently large n.
Definition (Combined upper and lower bound)
We say that f (n) is Θ(g (n)) if f (n) is both O(g (n)) and Ω(g (n)).
Definitions of asymptotic complexity
Let f (n) denote the number of operations needed for an algorithm to
solve a problem of size n. We use the following asymptotic notation. The
first definition is the most frequently used one.
Definition (Asymptotic upper bound)
We say that f (n) is O(g (n)) if there is a constant C such that
f (n) ≤ C · g (n) for all sufficiently large n.
Definition (Asymptotic lower bound)
We say that f (n) is Ω(g (n)) if there is a constant C such that
f (n) ≥ C · g (n) for all sufficiently large n.
Definition (Combined upper and lower bound)
We say that f (n) is Θ(g (n)) if f (n) is both O(g (n)) and Ω(g (n)).
Example
Consider the function f (n) = n3 . Then f (n) is
I O(n4 ) and O(n3 ),
I Ω(n3 ) and Ω(n2 ),
I Θ(n3 ).
Some basic rules for computing asymptotic complexity

1. The logarithmic function log(n) grows slower than a polynomial


function like n2 , which grows slower than a exponential function like
2n .
2. If f1 (n) is O(g1 (n)) and f2 (n) is O(g2 (n)), then f1 (n) · f2 (n) is
O(g1 (n) · g2 (n)).
3. Asymptotically, the sum of some functions is equal to the dominant
term.
Some basic rules for computing asymptotic complexity

1. The logarithmic function log(n) grows slower than a polynomial


function like n2 , which grows slower than a exponential function like
2n .
2. If f1 (n) is O(g1 (n)) and f2 (n) is O(g2 (n)), then f1 (n) · f2 (n) is
O(g1 (n) · g2 (n)).
3. Asymptotically, the sum of some functions is equal to the dominant
term.

Example (2.)
If f1 (n) is O(n2 ) and f2 (n) is O(log(n)), then f1 (n) · f2 (n) is O(n2 log(n)).
Some basic rules for computing asymptotic complexity

1. The logarithmic function log(n) grows slower than a polynomial


function like n2 , which grows slower than a exponential function like
2n .
2. If f1 (n) is O(g1 (n)) and f2 (n) is O(g2 (n)), then f1 (n) · f2 (n) is
O(g1 (n) · g2 (n)).
3. Asymptotically, the sum of some functions is equal to the dominant
term.

Example (2.)
If f1 (n) is O(n2 ) and f2 (n) is O(log(n)), then f1 (n) · f2 (n) is O(n2 log(n)).

Example (3.)
A polynomial p(n) = ak nk + ak−1 nk−1 + · · · a1 n + a0 is O(nk ).
Some basic rules for computing asymptotic complexity

1. The logarithmic function log(n) grows slower than a polynomial


function like n2 , which grows slower than a exponential function like
2n .
2. If f1 (n) is O(g1 (n)) and f2 (n) is O(g2 (n)), then f1 (n) · f2 (n) is
O(g1 (n) · g2 (n)).
3. Asymptotically, the sum of some functions is equal to the dominant
term.

Example (2.)
If f1 (n) is O(n2 ) and f2 (n) is O(log(n)), then f1 (n) · f2 (n) is O(n2 log(n)).

Example (3.)
A polynomial p(n) = ak nk + ak−1 nk−1 + · · · a1 n + a0 is O(nk ).

Example (1. and 3.)


The function log2 (n) + n3 + 3n is O(3n ).
Asymptotic complexity of a simple example algorithm

The worst-case complexity of an algorithm is the largest number of


operations performed by an algorithm on input of a given size.
Algorithm complexity is usually expressed with O-notation: we care about
the overall growth rate, not the precise constants of proportionality.

Example (Finding the maximum element in a list)


procedure max(a1 , . . . , an : integers)
max := a1
for i := 2, . . . , n do
if ai > max then
max := ai
return max
The algorithm performs n − 1 comparisons (ai > max). Hence its
(worst-case) complexity is O(n).
Linear or sequential search

The searching problem is the problem of locating an element x in a list


(finite sequence) of distinct elements a1 , a2 , . . . , an or determining that it
is not in the list.

Algorithm (Linear search)


Loop over all elements, test if they match x, quit once x is found.

procedure linear search(x integer, a1 , . . . , an : integers)


i := 1
while i ≤ n and x 6= ai do
i := i + 1
if i ≤ n then
location := i
else
location := 0
return location
Complexity:
I At every step of while loop, 2 comparisons are made.
I After while loop one more comparison is made.
I If x = ai , then 2i + 1 comparisons are made.
I In the worst case, x is not in the list. Then an extra comparison is
made for i = n + 1, and the total number of comparisons is 2n + 2
Hence the worst-case complexity is O(n).
Insertion sort

The sorting problem is the problem of ordering the elements of a list.

Algorithm (Insertion sort)


Insertion sort is how you sort a deck of cards, picking a card from the
deck and inserting it in the right location among the already sorted cards.
procedure insertion sort(a1 , . . . , an : real numbers with n ≥ 2)
for j := 2, . . . , n do
i := 1
while aj > ai do
i := i + 1
m := aj
for k := 0, . . . , j − i − 1 do
aj−k := aj−k−1
ai := m
return {a1 , . . . , an } in increasing order
I At the 1st step, the 2nd element is put in the right position relative
to the 1st element.
I At the 2nd step, the 3rd element is put in the right position relative
to the first two (sorted) elements.
I ...
I At the jth step, the (j + 1)st element is put in the right position
relative to the first j (sorted) elements.
I ...
I At the (n − 1)st step, the nth element is put in the right position
relative to the first n − 1 (sorted) elements.
I In the worst case, at the jth step, j + 1 comparisons (to the j
already sorted elements and to itself) are needed to put the (j + 1)st
element in the right position.
I Hence in the worst case (when we start with an already sorted list),
the total number of comparisons is
n−1
X n(n − 1) (n + 2)(n − 1)
(j + 1) = + (n − 1) =
2 2
j=1

Hence the (worst-case) complexity of insertion sort is O(n2 ).


Bubble sort

Algorithm (Bubble sort)


Successively compare adjacent elements:
procedure bubble sort(a1 , . . . , an : real numbers with n ≥ 2)
for i := 1, . . . , n − 1 do
for j := 1, . . . , n − i do
if aj > aj+1 then
m := aj
aj := aj+1
aj+1 := m
return {a1 , . . . , an } in increasing order
After one pass (i = 1), the last element is the largest element in the list.
Proof.
Let a = maxi ai . If in the original list an = a, it will still be there after
one pass, because any element (old or new) at position n − 1 will be
smaller than an (that is, the j = n − 1 comparison will have no effect.
If ak = a for some k < n, then by the same reasoning the j = k − 1
comparison has no effect and ak remains in place for the first k − 1 steps.
From the j = kth step onwards, aj > aj+1 will be true always, until at
last the old ak has moved down to the last position.
I The 1st pass guarantees that the largest element is in correct position.
I The 2nd pass guarantees that the 2 largest elements are in correct
position.
I ...
I The (n − 1)st pass guarantees that all elements are in correct position.

Figure 1: Bubble sort


I During the ith pass, n − i comparisons are made.
I Hence the total number of comparisons is
n−1
X n−1
X n(n − 1) n(n − 1)
(n − i) = n(n − 1) − i = n(n − 1) − =
2 2
i=1 i=1

Hence the (worst-case) complexity of bubble sort is O(n2 ).


We can write bubble sort as a recursive algorithm:

Algorithm (Bubble sort recursive)


procedure bubble sort(a1 , . . . , an : real numbers with n ≥ 2)
for j := 1, . . . , n − 1 do
if aj > aj+1 then
m := aj
aj := aj+1
aj+1 := m
if n = 2 then
return {a1 , a2 }
else
return {bubble sort(a1 , . . . , an−1 ), an }
Bubble sort takes input of size n and reduces the problem to sorting
input of size n − 1, needing n − 1 comparisons to do so.
Writing fn for the number of comparisons on input of size n, we get the
recurrence relation

fn = fn−1 + (n − 1)

with initial condition f2 = 1.


We propose a solution of the form fn = αn2 + βn. Plugging this into the
recurrence relation gives:

αn2 + βn = α(n − 1)2 + β(n − 1) + n − 1


(1 − 2α)n + (α − β − 1) = 0

This is true for all n if and only if 1 − 2α = 0 and α − β − 1 = 0, or


α = 12 and β = − 21 . Hence we find again:

n(n − 1)
fn =
2
Binary search
Searching for an element in a list can be done faster if the list is sorted.

Algorithm (Binary search)


procedure binary search(x integer, a1 , . . . , an : increasing integers)
i := 1
j := n
while i < j do
m := b(i + j)/2c
if x > am then
i := m + 1
else
j := m
if x = ai then
location := i
else
location := 0
return location
The complexity of binary search is best understood by taking n = 2k − 1,
and representing all possible comparisons x > am as a binary tree with
the midpoint values of m at the nodes.
The number of steps (= maximum number of comparisons) from the
root to one of the leaves is exactly k = log2 n.
Hence the worst-case complexity is O(log n)
Example (n = 15, x = a11 )
We test m = 8, 12, 10, 11
8

4 12

2 6 10 14
1 3 5 7 9 11 13 15
We can write binary search as a recursive algorithm:
Algorithm (Binary search recursive)
procedure binary search(x integer, a1 , . . . , an : increasing integers)
if n = 0 (empty list) then
location := 0
return location
else if x = am then
location := m
return location
else if x > am then
binary search(x, am+1 , . . . , an )
else
binary search(x, a1 , . . . , am−1 )
if x = ai then
location := i
else
location := 0
return location
Binary search takes input of size n, and reduces the problem to a search
on input of size n/2, needing two comparisons to do so: one to determine
whether the midpoint is the searched for element, and one to determine
whether to proceed with the left or right half of the list.
Let f (n) be the number of comparison in binary search for input of size
n. Then
n
f (n) = f +2
2
Taking again n = 2k and writing ak = f (2k ), we get a recurrence relation

ak = ak−1 + 2

with initial condition a1 = 1.


We propose that the solution is an arithmetic progression:

ak = a + dk

Plugging this into the recurrence relation and initial condition gives

a + dk = a + d(k − 1) + 2 a1 = a + d = 1
d =2 a = −1

Hence

f (2k ) = ak = 2k − 1

or

f (n) = 2 log2 (n) − 1

We find again that the worst-case complexity of binary search is


O(log n).
Matrices

An m × n matrix is a rectangular array of numbers with m rows and n


columns. If m = n, the matrix is called square. Two matrices are equal if
they have the same number of rows and columns and the same entries in
every position.
We write A = (aij ) as a shorthand for
 
a11 a12 ... a1n
 a21 a22 ... a2n 
 
A= . .. .. 
 .. . . 
am1 am2 ... amn

The sum of two m × n matrices A = (aij ) and B = (bij ) is the matrix


A + B = (aij + bij ).
The product of an m × r P
matrix A =(aij ) and r × n matrix B = (bij ) is
r
the m × n matrix AB = k=1 aik bkj .
Complexity of Matrix Operations

Let A and B be n × n matrices. The complexity of computing A + B is


clearly n2 = θ(n2 ).
Complexity of Matrix Operations

Let A and B be n × n matrices. The complexity of computing A + B is


clearly n2 = θ(n2 ).

In the product AB, every element is the result of a scalar product


between an n-dimensional row matrix and an n-dimensional column
matrix. This computation requires n multiplications and n − 1 additions.
Thus the total complexity of calculating all n2 elements is

n2 (n + (n − 1)) = 2n3 − n2 = θ(n3 ).

You might also like