2.2-1 Express the function n3/1000−100n2−100n+3 in terms of
θ−notation.
Solution:
The leading term of the function ignoring the constant coefficient is n3 . So, the function in θ−notation will be θ(n3).
2.2-2 Consider sorting n numbers stored in array A by first finding the smallest element of A and exchanging it with the element in A[1]. Then find the second smallest element of A, and exchange it with A[2]. Continue in this manner for the first n 1elements of A. Write pseudocode for this algorithm, which is known as selection sort. What loop invariant does this algorithm maintain? Why does it need to run for only the first n 1 elements, rather than for all n elements? Give the best-case and worst-case running times of selection sort in θ−notation? Justify your answers.
Solution:
Pseudocode
Loop invariants
At the start of each iteration of the inner for loop, A[min] is the smallest number in the subarray A[i..j−1].
Why n−1 elements?
In the final step, the algorithm will be left with two elements to compare. It will store the smaller one in A[n−1] and leave the larger in A[n]. The final one will be the largest element of the array, since all the previous iteration would have sorted all but the last two elements (the outer loop invariant). If we do it n times, we will end up with a redundant step that sorts a single-element subarray.
Running times
In the best-case time (the array is sorted), the body of the if is never invoked. The number of operations (counting the comparison as one operation) is:
θ−notation.
Solution:
The leading term of the function ignoring the constant coefficient is n3 . So, the function in θ−notation will be θ(n3).
2.2-2 Consider sorting n numbers stored in array A by first finding the smallest element of A and exchanging it with the element in A[1]. Then find the second smallest element of A, and exchange it with A[2]. Continue in this manner for the first n 1elements of A. Write pseudocode for this algorithm, which is known as selection sort. What loop invariant does this algorithm maintain? Why does it need to run for only the first n 1 elements, rather than for all n elements? Give the best-case and worst-case running times of selection sort in θ−notation? Justify your answers.
Solution:
Pseudocode
SELECTION-SORT(A): for i = 1 to A.length - 1 min = i for j = i + 1 to A.length if A[j] < A[min] min = j temp = A[i] A[i] = A[min] A[min] = temp
Loop invariants
At the start of each iteration of the inner for loop, A[min] is the smallest number in the subarray A[i..j−1].
Why n−1 elements?
In the final step, the algorithm will be left with two elements to compare. It will store the smaller one in A[n−1] and leave the larger in A[n]. The final one will be the largest element of the array, since all the previous iteration would have sorted all but the last two elements (the outer loop invariant). If we do it n times, we will end up with a redundant step that sorts a single-element subarray.
Running times
In the best-case time (the array is sorted), the body of the if is never invoked. The number of operations (counting the comparison as one operation) is:
$$ (n - 1)(\frac{n + 2}{2} + 4) $$
In the worst-case time (the array is reversed), the body of the if is invoked on every occasion, which doubles the number of steps in the inner loop, that is:
(n-1)(n+6)
Both are clearly Θ(n2).
2.2-3 Consider linear search again (see Exercise 2.1-3). How many elements of the input sequence need to be checked on the average, assuming that the element being searched for is equally likely to be any element in the array? How about in the worst case? What are the average-case and worst-case running times of linear search in ‚Θ-notation? Justify your answers.
Solution:
If the element is present in the sequence, half of the elements are likely to be checked before it is found in the average case. In the worst case, all of them will be checked. That is, n/2 checks for the average case and n for the worst case. Both of them are Θ(n).
2.2-4 How can we modify almost any algorithm to have a good best-case running time?
Solution:
We can modify it to handle the best-case efficiently. For example, if we modify merge-sort to check if the array is sorted and just return it, the best-case running time will be Θ(n).