$RUM60G1
$RUM60G1
$RUM60G1
- Use this word document to provide ALL your answers (code and text)
- Exam starts at 7 and is done at 10pm.
Q1.
Write a python function that get’s a list as an input and the midrange of its values. Midrange is the midway
point the minimum and the maximum of the data set
Example: midrange of [5, 4, 8, 2, 9, 1, 3] is 5 and median of [4, 5, 2, 1, 7, 7] is (7+1)/2 = 4 . You
can use python’s own sorting algorithm.
def find_midrange(lst):
sorted_lst = sorted(lst)
minimum_no = sorted_lst[0]
maximum_no = sorted_lst[-1]
return midrange
Q2.
Write a python function that gets n and returns the nth value in the fun function sequence. Fun function
sequence is defined by
P(n) = 3*P(n-1) + 2*P(n-2) while P(0) = 0 and P(1) = 1. Use your code to generate and provide the first 10
values of fun function sequence.
def fun(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return 3 * fun(n-1) + 2 * fun(n-2)
Q3.
Run an analysis of the function developed in Q2 and find its T(n) and big O perforamance. Is finding the nth
element of Fun function sequence faster than bubble sort? Is it faster than finding the nth element of the
Fibonacci series?
Solution:
3. For n = 3, fun(2) requires two more recursive calls and fun(1) returns immediately.
4. For n = 4, fun(3) requires four more recursive calls and fun(2) requires two more recursive calls.
Therefore, the number of recursive calls doubles for each increase in n. In general, for n levels of recursion,
the number of recursive calls can be approximated by 2^n.
Time complexity:
Comparatively, the Fun function sequence grows exponentially with the input size, while Bubble sort grows
quadratically.
For larger values of n, calculating the nth element of the Fun function sequence is generally faster than
executing Bubble sort.
Time complexity:
Q4.
What is the T(n) and big O performance of the following function? This function gets a value as an input and
prints all prime numbers between 1 and the input number. Math.sqrt takes the square root of a number
import math def
print_all_primes(n): for
num in range(1,n + 1):
isPrime = True for i in
range(2,int(1+math.sqrt(num))):
if num % i ==0 :
isPrime = False
break if isPrime:
print(num)
Solution:
In terms of the big O notation, we can simplify the expression to O(n^(3/2)), as the sqrt(n) term dominates the
n term in the time complexity.
Which one is faster? sorting a list of size n or to printing all prime numbers up to n? Answer based on
both bubble sort and merge sort.
1. Bubble Sort: Bubble sort has a worst-case time complexity of O(n^2).
2. Merge Sort: Merge sort has a worst-case time complexity of O(n log n).
3. Printing all prime numbers up to n: The T(n) for printing all prime numbers up to n is O(n *sqrt(n)).
In terms of time complexity, both sorting algorithms (bubble sort and merge sort) are slower than printing all
prime numbers up to n, as the time complexity of printing primes is lower than O(n^2) or O(n log n). Therefore,
for larger values of n, printing all prime numbers up to n would generally be faster than sorting a list using
either bubble sort or merge sort.
Q5.
Assume that that after analysing a recursive function to find it’s T(n) you find that T(n)
= 5 + 2 * T(n/4)
What is the big O performance of this function? Is it faster or slower than binary search? Is it faster or slower
than merge sort?
Hint: a ^ ( log x in base a^k) = x^(1/k)
After analyzing the relation, we notice that the function divides the problem size by a factor of 4 in each
recursive call. Therefore, we can approximate the big O performance of the function as O(log n) with a base of
4.
Binary Search:
The given recursive function (O(log n) base 4) is slower than binary search (O(log n) base 2) because binary
search performs fewer operations.
Merge Sort:
The given recursive function (O(log n)) is faster than merge sort (O(n log n)) in terms of the number of
operations performed. However, merge sort has better overall performance as it guarantees a sorted output.
Q6.
What are advantages and disadvantages of using singly linked lists vs. doubly linked lists? Please elaborate
Solution:
Q7.
Assume that a linked list is declared as follows:
that gets a linked list myLList and builds the linked list based on the given myLList by:
clone_range : copying over all elements of myLlist that are larger or equal to min and smaller or equal to
max
Hint: You can first implement a simple insert function for your linked list that gets a node (or data) and insets it
in the list. Then in the clone_range function, iterate the given myLList and one by one insert the qualified data
into.
Solution:
# Traverse from ith to jth element and store data in reverse order
for data in range(i, j+1):
if curr_value is None:
break
data_lst.insert(0, curr_value.data)
curr_value = curr_value.next
return tmp_lst
curr_value = myLList.front
# Traverse the given list and insert qualified data into the new list
tmp_lst.insert(curr_value.data)
curr_value = curr_value.next
return tmp_lst
Using the double hash functions above, do the following two insertions
Insert(Key = 0, value = Plum)
Insert(Key = 9, value = Strawberry)
Just provide a simple explanation and populate the values in the table above. No coding required.
Solution:
1. Insertion with Key = 0, Value = Plum:
Using the first hash function: hash1(0) = 0 % 13 = 0.
Since index 0 is already occupied by the key 11, we need to handle the collision.
Applying the second hash function: hash2(0) = 9 - (0 % 9) = 9.
We encounter a collision at index 9.
Following the double hashing approach, we increment the index by the result of the second
hash function.
We get index 10, which is also not available.
Now we increment it by1 until we find an empty index, the next empty index is 1.
Therefore, we insert the Key = 0 and Value = Plum at index 1 in the table.
Updated table