- Alejandro Madrigal
- Owen Mastropietro
CLI
$ python3 project01a.py
- Follow the prompts for entering significant data.
PyCharm
- Under "configurations", set script path to the python "project01a" file.
- Select "run" located in the upper-right corner of the application.
- Follow the prompts for entering significant data.
- Euclid's Algorithm for finding the Greatest Common Divisor, GCD.
- Iterative and Recursive Functions to return the n'th number in the Fibonacci sequence.
- Three techniques for an exponentiation function to compute an.
- Selection Sort.
- Insertion Sort.
For this project, we were tasked with exploring the upper bounds of Euclid's Algorithm for computing the Greatest Common Divisor, GCD, exploring three different techniques for computing a2, and exploring two common sorting algorithms, insertion sort and selection sort.
Implement an algorithm for computing the Greatest Common Divisor of two integers
def euclid_GCD(m, n):
if n == 0: return m, 0
if n == 1: return 1, 0
else:
val, basic_operation_count = euclidGCD(n, m % n)
return val, basic_operation_count + 1
- Time Complexity: Θ(n) --> Θ(2b)
- Asymptotic Complexity Scatter Plot:
Implement an algorithm, that returns the k'th number in the fibonacci sequence
def fib(k):
if k == 0: return 0, 0
if k == 1: return 1, 0
else:
val_1, basic_ops_1 = fib(k-1) # where val_1 = fib(k-1)[0] and basic_ops_1 = fib(k-1)[1]
val_2, basic_ops_2 = fib(k-2)
return val_1 + val_2, basic_ops_1 + basic_ops_2 + 1
- Time Complexity: Θ(phik) or Θ(phi2b)
- Asymptotic Complexity Scatter Plot:
Explore GCD(fib(k+1), fib(k))
- TODO
Exponentiation Algorithms for computing ax.
Technique 1: Decrease by One
def exp1(a, n):
if n == 0: return 1, 0 # Note: a^0 = 1 for all values of a.
if n == 1: return a, 0 # Note: a^1 = a for all values of a.
else:
val, basic_operation_count = exp1(a, n-1)
return a * val, basic_operation_count + 1
- Basic operation: Multiplication
- Recurrence Relation: M(n) = M(n - 1) + 1 1
- Time Complexity: Θ(n) ==> Θ(2b)
- Proof:
- Note that 'M(n - 1)' represents the number of basic operations in computing exp_1(a, n-1).
- Note that '+ 1' represents the additional basic operation/multiplication in computing a * exp_1(a, n-1).
- Since the basic operation is not activated on M(1), we rely on M(1) = 0 for solving our recurrence relation.
- M(n) = M(n - 1) + 1
- = [M(n - 2) + 1] + 1
- = [M(n - 3) + 1] + 2
- = M(n - 3) + 3
- Given the pattern, we assume the i'th instance of this relation can be expressed as follows:
- M(n) = M(n - i) + i where i = n - 1
- = M(1) + n - 1
- = n - 1
- M(n) = n - 1 exists in Θ(n) -- Θ(2b)
Technique 2: Decrease by Constant Factor
def exp2(a, n):
if n == 0: return 1, 0 # Note: a^0 = 1 for all values of a.
if n == 1: return a, 0 # Note: a^1 = a for all values of a.
elif n % 2 == 0: # If n is even:
val, basic_operation_count = exp2(a, n/2)
return val ** 2, basic_operation_count + 1 # Increment basic_operation_count by one due to squaring.
else: # If n is odd:
val, basic_operation_count = exp2(a, (n-1) / 2)
return a * val ** 2, basic_operation_count + 2 # Increment basic_operation_count by two due to squaring and multiplying.
- Basic operation: Multiplication
- Recurrenc Relation: M(n) = M(n/2) + 1
- Time Complexity: Θ(log n)
- Proof:
- Since the basic operation is not activated on M(1), we rely on M(1) = 0 for solving our recurrence relation.
- Let n = 2k such that 2k / 2 = 2k - 1.
- M(2k) = M(2k - 1)) + 1
- = [M(2k - 2) + 1] + 1
- = [M(2k - 3) + 1] + 2
- = M(2k - 3) + 3
- Given the pattern, we assume the i'th instance of this relation can be expressed as follows:
- M(2k) = M(2k - i) + i where i = k
- = M(1) + k
- M(2k) = k
- M(n) = log n exists in Θ(log n) -- Θ(b) 2
Technique 3: Divide and Conquer
def exp3(a, n):
if n == 0: return 1, 0 # Note: a^0 = 1 for all values of a.
if n == 1: return a, 0 # Note: a^1 = a for all values of a.
elif n % 2 == 0: # If n is even:
val, basic_operation_count = exp3(a, n/2)
return val * val, basic_operation_count + 1 # Increment basic_operation_count by one due to single multiplication of val * val
else: # If n is odd:
val, basic_operation_count = exp3(a, (n-1)/2) # According to the project page, (n-1)/2. However, everywhere online uses n/2 and it does not seem to effect the result.
return a * val * val, basic_operation_count + 2 # Increment basic_operation_count by two due to two multiplications of a * val * val.
- Recurrence Relation: here
- Time Complexity: Θ(n) 3
- Proof:
- TODO
- Asymptotic Complexity Scatter Plot:
Insertion Sort
def insertion_sort(arr_in, n):
basic_operation_count = 0
arr = arr_in.copy()
i = 0
while i < n:
j = i
while j > 0 and arr[j] < arr[j-1]:
arr[j], arr[j-1] = arr[j-1], arr[j]
basic_operation_count += 1
j = j - 1
basic_operation_count += 1
i = i + 1
return arr, basic_operation_count
- Recurrence Relation:
- Best: C(n) = n - 1
- Average: C(n) = n(n - 1) / 2
- Worst: C(n) = n(n - 1) / 2
- Time Complexity:
- Best: O(n)
- Average: O(n2)
- Worst: O(n2)
Selection Sort
def selection_sort(arr_in, n):
basic_operation_count = 0
arr = arr_in.copy()
i = 0
while i < n-1:
bigIdx = 0
j = 1
while j < n-i:
if arr[j] > arr[bigIdx]:
bigIdx = j
basic_operation_count += 1
j = j + 1
arr[bigIdx], arr[n-i-1] = arr[n-i-1], arr[bigIdx] # swap(arr, bigIdx, n-i-1)
i = i + 1
return arr, basic_operation_count
-
Recurrence Relation: here
-
Time Complexity: Θ(n2)
-
Asymptotic Complexity Scatter Plot:
Footnotes
-
Decrease by One Exponentiation The recurrence relation A(n-1) + 1 is built on A(n-1) representing the number of basic operations in computing exp_1(a, n-1) and '+ 1' representing the additional basic operation in computing a x exp1(a, n-1). ↩
-
As per the textbook, on page 133, we are reducing the problem size by about half at the expense of one or two multiplications. This suggests that this algorithm is in Θ(log n). ↩
-
Not O(n log n) or O(log n)... More Operations than Decrease by Constant Factor due to recursive calls having to do work. exp(a, n) * exp(a, n) vs exp(a, n)2. ↩