Here are suggested solutions to the exercises about complexity, part A.
f1. The loop body runs n times. In each iteration, the result increases by one. Thus, T(n) = n ∈ O(n) (linear complexity).
f2. The outer loop has n iterations. In each iteration, the inner loop body runs n–1 times. In each iteration, the result increases by one. Thus, T(n) = n(n–1) ∈ O(n2) (quadratic complexity).
f3. The body of the outer loop runs n times, ranging over i = 1, 2, …, n. In each iteration, the inner loop body runs i times, which is (n+1)/2 on average. In each iteration, the result increases by one. In total, this increases the result by 1 + 2 + … + n = (n+1)/2 + (n+1)/2 + … + (n+1)/2 = n(n+1)/2. Thus, T(n) = n(n+1)/2 ∈ O(n2) (quadratic complexity).
Note: The growth rate of the sum 1 + 2 + … + n can be determined without knowing the closed formula for it: T(n) = 1 + 2 + … + n ≤ n ∙ n = n2 ∈ O(n2).
f4. The outer loop has ⌊n/4⌋ iterations. In each iteration, the middle loop runs ⌊n/9⌋ times, and in each of its iterations, the inner loop body runs ⌊n/25⌋ times. Thus, T(n) = ⌊n/4⌋·⌊n/9⌋·⌊n/25⌋ ≤ n3/(4·9·25) ∈ O(n3).
f5. The body of the first loop runs n times; in each iteration, the result increases by one. The same happens with the second loop, except it has n+1 iterations. Thus, T(n) = n + (n+1) ∈ O(n) (linear complexity).
f6. Let us first look at the nested loops at the start. It is the same as in f3, so it runs n(n+1)/2 times. The body of the loop at the end runs n times, so it increases the final result by n. Thus, T(n) = n(n+1)/2 + n ∈ O(n2) (quadratic complexity).
Insertion sort has worst-case complexity O(n2) and average-case complexity O(n2).
Merge sort has worst-case complexity O(n log(n)) and average-case complexity O(n log(n)).
Quicksort has worst-case complexity O(n2) and average-case complexity O(n log(n)), assuming a uniform distribution of input orderings. An elegant proof can be found here.
In a sorted array, duplicate elements appear in right after one another. So to check for duplicates, it suffices for 0 ≤ i < n–1, to check if a[i] equals a[i+1].
Here is a rough sketch of the program:
We leave the details of actually turning it into a working program as an exercise for you! Regarding the two questions:
See the lecture slides for Stacks & Queues.
f7. The outer loop has [log2(n) + 1] iterations, and each time the inner loop body runs n times. In total, T(n) = [log2(n) + 1] n ∈ O(n log(n)).
f8. The outer loop ranges over i = 1, 2, 22, …, 2m where m is maximal such that 2m ≤ n. This means m = ⌊log2(n)⌋, so the outer loop has 1 + ⌊log2(n)⌋ iterations. In each iteration, the inner loop runs n2 times. In each iteration, the result increases by one. Thus, T(n) = (1 + ⌊log2(n)⌋) n2 ∈ O(n2 log(n)).
f9: (This one is trickier that it seems)