CMPUT 175 Lecture #3
CMPUT 175 Lecture #3
Introduction to Foundations
of Computing
Algorithm Analysis
def sum2(n):
if n==0: return 0
else: return sum2(n-1) + n
44.48 seconds
0.05 seconds
def sum3(n):
return (n*(n+1))/2
January 22, 2024 © Osmar R. Zaïane : University of Alberta 15
def sum1(n):
Benchmarking 3
n=100000000 theSum=0
totalTime=0.0 for i in range(1,n+1):
for i in range(5): theSum=theSum+i
start=time.time() return theSum
x=sum1(n)
end=time.time()
Repeating sum1 while varying n print("the sum is %d and it required %10.7f seconds"%(x,end-start))
totalTime=totalTime+end-start
print("with sum1 the average time was %10.7f for n=%d"%(totalTime/5,n))
n= 100,000 n= 1,000,000
the sum is 5000050000 and it required 0.0156250 seconds the sum is 500000500000 and it required 0.1250000 seconds
the sum is 5000050000 and it required 0.0156250 seconds the sum is 500000500000 and it required 0.1250000 seconds
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.1250000 seconds
the sum is 5000050000 and it required 0.0156250 seconds the sum is 500000500000 and it required 0.1250000 seconds
the sum is 5000050000 and it required 0.0156250 seconds the sum is 500000500000 and it required 0.1250000 seconds
with sum1 the average time was 0.0125000 for n=100000 with sum1 the average time was 0.1250000 for n=1000000
n= 10,000,000 n= 100,000,000
the sum is 50000005000000 and it required 1.2343750 seconds the sum is 5000000050000000 and it required 12.5156250 seconds
the sum is 50000005000000 and it required 1.2343750 seconds the sum is 5000000050000000 and it required 12.5312500 seconds
the sum is 50000005000000 and it required 1.2500000 seconds the sum is 5000000050000000 and it required 12.3437500 seconds
the sum is 50000005000000 and it required 1.2656250 seconds the sum is 5000000050000000 and it required 12.3125000 seconds
the sum is 50000005000000 and it required 1.2187500 seconds the sum is 5000000050000000 and it required 12.5312500 seconds
with sum1 the average time was 1.2406250 for n=10000000 with sum1 the average time was 12.4468750 for n=100000000
n= 100,000 n= 1,000,000
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.0000000 seconds
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.0000000 seconds
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.0000000 seconds
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.0000000 seconds
the sum is 5000050000 and it required 0.0000000 seconds the sum is 500000500000 and it required 0.0000000 seconds
with sum3 the average time was 0.0000000 for n=100000 with sum3 the average time was 0.0000000 for n=1000000
n= 10,000,000 n= 100,000,000
the sum is 50000005000000 and it required 0.0000000 seconds the sum is 5000000050000000 and it required 0.0000000 seconds
the sum is 50000005000000 and it required 0.0000000 seconds the sum is 5000000050000000 and it required 0.0000000 seconds
the sum is 50000005000000 and it required 0.0000000 seconds the sum is 5000000050000000 and it required 0.0000000 seconds
the sum is 50000005000000 and it required 0.0000000 seconds the sum is 5000000050000000 and it required 0.0000000 seconds
the sum is 50000005000000 and it required 0.0000000 seconds the sum is 5000000050000000 and it required 0.0000000 seconds
with sum3 the average time was 0.0000000 for n=10000000 with sum3 the average time was 0.0000000 for n=100000000
n= 100,000 n= 1,000,000
the sum is 5000050000 and it required 0.0468750 seconds the sum is 500000500000 and it required 0.0468750 seconds
the sum is 5000050000 and it required 0.0468750 seconds the sum is 500000500000 and it required 0.0468750 seconds
the sum is 5000050000 and it required 0.0625000 seconds the sum is 500000500000 and it required 0.0468750 seconds
the sum is 5000050000 and it required 0.0468750 seconds the sum is 500000500000 and it required 0.0468750 seconds
the sum is 5000050000 and it required 0.0468750 seconds the sum is 500000500000 and it required 0.0468750 seconds
with sum3 the average time was 0.0500000 for n=100000 with sum3 the average time was 0.0468750 for n=1000000
n= 10,000,000 n= 100,000,000
the sum is 50000005000000 and it required 0.0468750 seconds the sum is 5000000050000000 and it required 0.0625000 seconds
the sum is 50000005000000 and it required 0.0468750 seconds the sum is 5000000050000000 and it required 0.0781250 seconds
the sum is 50000005000000 and it required 0.0468750 seconds the sum is 5000000050000000 and it required 0.0625000 seconds
the sum is 50000005000000 and it required 0.0468750 seconds the sum is 5000000050000000 and it required 0.0625000 seconds
the sum is 50000005000000 and it required 0.0468750 seconds the sum is 5000000050000000 and it required 0.0625000 seconds
with sum3 the average time was 0.0468750 for n=10000000 with sum3 the average time was 0.0656250 for n=100000000
sum3
n
January 22, 2024 © Osmar R. Zaïane : University of Alberta 19
8
13
1
2
1
5
3
Leonardo Pisano
def sum2(n):
Recursion if n==0: return 0
else: return sum2(n-1) + n
0 1st 2nd 3rd 4th 5th 6th 7th …........ …………… 35th ?
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144…..
a=b
b=c
print(fibonacci(35))
For example for fibonacci(4) 9227465
fibonacci(4) calls fibonacci(3) and fibonacci(2)
fibonacci(3) calls fibonacci(2) and fibonacci(1) 4
fibonacci(2) calls fibonacci(1) and fibonacci(0) 3 2
fibonacci(1) terminates with 1
fibonacci(0) terminates with 0 2 1 1 0
fibonacci(1) terminates with 1 1 0
fibonacci(2) calls fibonacci(1) and fibonacci(0)
fibonacci(1) terminates with 1
fibonacci(0) terminates with 0
January 22, 2024 © Osmar R. Zaïane : University of Alberta 26
A recursive program with cache
Algorithm memFibo = {0:0, 1:1}
M[0]=0
M[1]=1 def fib(n):
F(n) { if not n in memFibo:
if not exist M[n] memFibo[n] = fib(n-1) + fib(n-2)
M[n]= F(n-1) + F(n-2) return memFibo[n]
return M[n]
} print(fib(35))
9227465
Avoids recalculating numbers in the
Fibonacci sequence that were already
calculated.
January 22, 2024 © Osmar R. Zaïane : University of Alberta 27
Another solution
Algorithm
1 5
5
1.6180339887 498948 also known as the Golden ratio
2
def fibonacci(n):
inverseSqrt5 = 0.44721359549995793928183473374626
phi = 1.6180339887498948482045868343656
x=pow(phi,n)
return int(round(x*inverseSqrt5))
print(fibonacci(35))
9227465
January 22, 2024 © Osmar R. Zaïane : University of Alberta 28
Which program is better?
All four solutions are correct, but which
one is the best? Measure the running time
fib1(): iterative fib2(): recursive fib3(): recursive with cache fib4(): Golden ratio
print(fibonacci(35)) 9227465
January 22, 2024 © Osmar R. Zaïane : University of Alberta 31
Divide and Conquer for the
Power function
Xn can be computed by multiplying X by itself n times iteration
X * X *…..*X
n times or we can divide the problem to reduce the computation
n n
X X X
n 2 2 if n is even
n 1 n 1
x4=x2 * x2
x7=x3 * x3 * x X 2
X 2
X if n is odd
2
a b a b a b aa+bc ab+bd
= c d c d =
c d ca+dc cb+dd
a b a b a b a b a b a b a b a b
c d c d c d c d c d c d c d c d
120.00000000
fib1(): iterative 0.00018000
0.00004000
20.00000000
0.00400000 0.00002000
0.00000000 0.00000000
0.00350000
10 20 = 30 = 40 = 50 = 60 = 70 = 80 = 90 100 000
00
n= n=
n= 0
10
20
30
40
50
60
70
80
90
n n n n n n n n= n= 1
10
10
n=
n=
n=
n=
n=
n=
n=
n=
n=
0.00300000
n=
0.00250000
fib1()
0.00200000
fib1(): Tfib1(n)=n fib5()
0.00150000 Some could not continue
fib2(): Tfib2(n)=φn 0.00100000 fib2(): Exponential
fib3(): Tfib3(n)=n 0.00050000 fib3(): recursion depth too deep
fib4(): Tfib4(n)=log(n) 0.00000000 fib4(): error +
0
n= 00
n= 0
10
20
30
40
50
60
70
80
90
n=
n=
n=
n=
n=
n=
n=
n=
fib5(): Tfib5(n)=log(n)
10
n=
n
(size)
January 22, 2024 © Osmar R. Zaïane : University of Alberta 41
Function of Growth rate
Big-O notation
Greedy Algorithm
Take the best one can get in each step
Recursion
January 22, 2024 © Osmar R. Zaïane : University of Alberta 46
Dynamic programming
Use a table to store intermediate results
Avoid repeat computation
The Fibonacci numbers
def fibonacci(n):
if n == 0 or n == 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
January 22, 2024 © Osmar R. Zaïane : University of Alberta 47
The function The number of calls
F(5) 1
F(4) 2
F(3) 3
F(2) 5
F(1) 7
F(0) 5
def fib(n):
if not n in memFibo:
memFibo[n] = fib(n-1) + fib(n-2)
return memFibo[n]
1 1 1 1 1 1 1 1 1 1
1 0 1 0 1 0 1 0 1 0
2 1 2 1 1 1
1 1 1 1 1 0
8 5 8 5
5 3 5 3
89 55 1 1
55 34 1 0
Only four 2x2 matrix multiplications
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89,..., 144 89
in a sequence of 11 89 55
January 22, 2024 © Osmar R. Zaïane : University of Alberta 53
Fibonacci with matrices
def fibonacii(n):
def matrixPower(a,b,c,d,n):
(a,b,c,d) = matrixPower(1,1,1,0,n)
if n<=1: return (1,1,1,0)
return b
elif n%2==0:
# x^n = x^(n/2) * x^(n/2)
(a1,b1,c1,d1)=matrixPower(a,b,c,d,n/2)
a3=a1*a1+b1*c1
b3=a1*b1+b1*d1 aa+bc ab+bd
c3=c1*a1+d1*c1 I didn’t call matrixPower
d3=c1*b1+d1*d1
ca+dc cb+dd
else:
again. I simply multiplied
# x^n = x^((n-1)/2) * x^((n-1)/2) * x the matrix result (a1, b1, c1, d1)
(a1,b1,c1,d1)=matrixPower(a,b,c,d,(n-1)/2)
a2=a1*a1+b1*c1 # x^((n-1)/2) * itself by itself
b2=a1*b1+b1*d1
c2=c1*a1+d1*c1
d2=c1*b1+d1*d1
a3=a2*a+b2*c # x^n = x^(n-1) * x
The same here
b3=a2*b+b2*d
c3=c2*a+d2*c
d3=c2*b+d2*d
return a3,b3,c3,d3
…
t=timeit.Timer("list1()","from __main__ import list1")
print("Concatenation: %17.14f milliseconds"%(t.timeit(number=1000)))
index [] O(1)
index assignment O(1)
append O(1)
pop() O(1)
pop(i) O(n)
insert(i,item) O(n)
del operator O(n)
iteration O(n)
contains (in) O(n)
get slice [x:y] O(k)
del slice O(n)
set slice O(n+k)
reverse O(n)
concatenate O(k)
sort O(n log n)
multiply O(nk)
January 22, 2024 © Osmar R. Zaïane : University of Alberta 61