CMPSC 465 Assignment 2
CMPSC 465 Assignment 2
CMPSC 465 Assignment 2
Format Requirement
Algorithms in pseudo code MUST be placed in code blocks/fences (5%), and use
either the cpp or java syntax highlighter.
Algorithms should follow the pseudo code standard described in handout 1. (2%)
Algorithm alg_name(a, b) {
// A description of the algorithm
// input: a - a positive decimal integer; b - an integer
// ouput: the sum of a and b
c = a + b // or, c <- a + b
return c
}
Formulas and equations should be in math mode using Latex math symbols. (5%)
click the ... button at the top right of your notion page
Problem 1
Consider a variation of sequential search that scans a list to return the number of
occurrences of a given search key in the list. Does its efficiency differ from the efficiency
of classic sequential search?
Answer:
Asymptotically, no. However, in the average case there is a constant factor difference.
There is no worst / best / average case for sequentially going through a list to find the
frequency of an element, since you always need to go through the entire list.
While performing regular sequential search, the best case is finding the key at the first
element, and the average case is traversing half of the elements in the list before finding
the key, making it twice as fast as the other variant of sequential search on average.
Problem 2
The range of a finite nonempty set of n real numbers S is defined as the difference
between the largest and smallest elements of S . For each representation of S given
below, describe an algorithm in pseudo code to compute the range. Indicate the time
efficiency classes of these algorithms using Big- O .
1. An unsorted array
2. A sorted array
Answer:
Algorithm rangeSortedLinkedList(head) {
// Computes the range of an linked list
// input: head - head of linked list
// ouput: the range of the linked list
minVal = head->val
maxVal = head->val
Algorithm rangeBST(root) {
// Computes the range of an BST
// input: root - root of BST
// ouput: the range of the BST
leftNode = root
rightNode = root
Problem 3
Compute the following sums (you need to provide detailed steps) :
1. 1 + 3 + 5 + 7 + ⋯ + 999
n−1 i−1
2. ∑i=0 ∑j=0 (i + j)
Answer:
Part 1
500 500
This sum is equal to ∑i=1 2i − 1 = (2 ∑i=1 i) − 500.
500×501
This can be simplified to 2( 2 )− 500 = 500 × 500 = 25000.
Part 2
(i−1)i
∑i=0 i2 + 3
∑i=0 i2 − 12 ∑i=0 i
n−1 n−1 n−1
2 = 2
3 3 (n−1)n(2n−1) (n−1)n
∑i=0 i2 − 12 ∑i=0 i =
n−1 n−1
2 2 6 − 4
Problem 4
Algorithm Mystery(n) {
// Input:A nonnegative integer n
S = 0;
for i = 1 to n do {
S = S + i * i;
}
return S
}
Answer:
Part 1
Part 2
The basic operation is multiplication (addition or assignment can also be chosen).
Part 3
Part 4
Part 5
Problem 5
Consider the following algorithm:
Answer:
Part 1
Part 2
Part 4
Part 5
A better algorithm does not exist for unsorted arrays. To see this, note that it takes
O(n) time simply to check all the elements in the array; and without looking at all the
elements of the array, we cannot guarantee that we have the minimum and maximum of
an array (and hence have computed the correct value for its range). Hence any
algorithm to compute the range of an array must take at least O(n) time. Of course,
constant factor improvements are possible in practice, using techniques such as loop
unrolling and multiprocessing.
Problem 6
Consider the following recursive algorithm for computing the sum of the first $n$ cubes:
S(n) = 13 + 23 + ⋯ + n3 .
ALGORITHM S(n) {
//Input: A positive integer n
//Output: The sum of the first n cubes
if n == 1 return 1;
else return S(n - 1) + n * n * n;
}
1. Set up and solve a recurrence relation for the number of times the algorithm’s basic
operation is executed.
2. How does this algorithm compare with the straightforward non-recursive algorithm
for computing this sum?
Answer:
Part 1
Part 2
The time complexity of this algorithm versus directly summing each term is the same
(both are O(n)). However, in practice the recursive solution will be slower due to the
overheads of recursion - performing stack operations to manage recursive calls, and
additional memory usage. Additionally, it is possible to compute this sum in O(1) time
using the formula
n2 (n−1)2
∑ni=1 i3 = 4
.
Problem 7
Consider the following recursive algorithm
ALGORITHM Q(n) {
//Input: A positive integer n
if n == 1 return 1;
else return Q(n - 1) + 2 * n - 1;
}
1. Set up a recurrence relation for this function’s values and solve it to determine what
this algorithm computes.
2. Set up a recurrence relation for the number of multiplications made by this algorithm
and solve it.
Answer:
Part 1:
The recurrence relation for the return value is: Q(n) = Q(n − 1) + 2n − 1. The base
case is Q(1) = 1 = 2(1) − 1.
Then, using backward substitution, we get:
Part 2:
Let the basic operation being considered be multiplication. Then we have T (n) = 1 +
T (n − 1), and the base case is T (1) = 0. Solving this gives T (n) = n − 1, which
makes T (n) ∈ O(n).
Problem 8
Consider the following recursive algorithm.
2. Set up a recurrence relation for the algorithm’s basic operation count and solve it.
Answer:
Part 1:
This algorithm finds the minimum value in an array.
Part 2:
The basic operation here is the indexing operation (assignment, lesser than check can
also be chosen), which is used either once or twice in every function call. In either case,
the work done is constant, so we can simply consider just 1 basic operation in each
function call.
Problem 9
Consider the following algorithm to check whether a graph defined by its adjacency
matrix is complete.
Answer:
The worst case input for this algorithm is when the graph is complete. In this case, the
algorithm will take O(n2 ) time. This is because the for loop in every recursive call
except the call that is the base case (every call GraphComplete(A[ 0..i, 0..i ] for 1 <i<
n)) will execute the for loop in the nested else block.
The basic operation (considered to be checking for equality) is performed once, plus
once every iteration from 0 to i − 1, for a total of i + 1 times, in the function
call GraphComplete(A[ 0..i, 0..i ]) .
The recurrence relation for the number of basic operations will be T(n) = n + 1 + T(n -
1), with the base case being T(0) = 1.
Thus, the number of basic operations in all the recursive calls will be (n + 1) + n +
(n+1)(n+2)
(n − 1) + (n − 2) + (n − 3) + (n − 4) … . + 3 + 2 + 1 = 2
, which
makes T (n) ∈ O(n2 ).