# Analysis of Algorithms II

## Presentation on theme: "Analysis of Algorithms II"— Presentation transcript:

Analysis of Algorithms II

Key Topics * Solving Recurrence Relations * The Towers of Hanoi
* Analyzing Recursive Subprograms

Recurrence Relations Recall that a recursive or inductive definition has the following parts: Base Case: the initial condition or basis which defines the first (or first few) elements of the sequence Inductive (Recursive) Case: an inductive step in which later terms in the sequence are defined in terms of earlier terms. A recurrence relation for a sequence a1, a2, a3, ... is a formula that relates each term a k to certain of its predecessors ak-1, ak-2, ..., a k-i, where i is a fixed integer and k is any integer greater than or equal to i. The initial conditions for such a recurrence relation specify the values of a1, a2, a3, ..., ai-1.

Example 1 Set of all bit strings of form 0 ----- K-1 bits without 11
a) One way to solve this problem is enumeration: length 0: empty string length 1: 0, length 2: 00, 01, 10, length 3: 000, 001, 010, 011, 100, 101, 110, b) Suppose the number of bit strings of length less than some integer k that do not contain the 11 pattern is known (it just so happens that we do know it for 0, 1, 2, 3). To find the number of strings of length k that do not contain the bit pattern 11, we can try to express strings that have a certain property in terms of shorter strings with the same property. This is called recursive thinking. Set of all bit strings of form K-1 bits without 11 Set of all bit strings of form 10 --- k-2 bits without 11

A Recurrence Relation:
1) s0 = s1 = 2 2) s k = sk-1 + sk-2 If we calculate this recurrence to s10, we get 144

Example 2 Consider the following recurrence relation: a0 = 1
a k = a k-1 + 2 Problem: What is the formula for this recurrence relation? We start by substituting k-1 into the recursive definition above to obtain: ak-1 = ak-2 +2 What we are looking for is a lot of different representations of the formula for ak based on previous elements in the sequence: a k = a k = (a k-2 + 2) + 2 = a k-2 + 4 we substitute k-2 for k in the original equation to get a k-2 = a k and then substitute this value for a k-2 in the previous expression: a k = a k = (a k-3 + 2) + 4 = ak-3 + 6 a k = a k = (a k-4 + 2) + 6 = ak-4 + 8 a k = a k

Proof: Let P(n) denote the following: if a1, a2, a3, ..., an is the sequence defined by: A 0 = 1 A k = ak then, an = 1 + 2n for all n >= 1 Base Case: prove that P(1) is true. Using the definition of the recurrence relation, we have: a1 = a0 + 2 = = 3. Now, we show that we get the same answer using the formula: an = 1 + 2n for n = 1. an = 1 + 2n = = 3. Therefore, the base case holds. Inductive Case: The induction hypothesis is to assume P(k): ak = 1 + 2k. We then need to show that P(k+1) = ak+1 = 1 + 2(k + 1). ak+1 = a((k+1)–1) from the recurrence relation (this is a "given") ak+1 = ak + 2 algebra ak+1 = 1 + 2k substitution from inductive hypothesis (ak = 1 + 2k) ak+1 = 1 + 2(k + 1) algebra

Example 3 Enumerating the first few values of this sequence yields:
K2 = K1 + 1 = = 1 K3 = K2 + 2 = = 3 K4 = K3 + 3 = = 6 K5 = K4 + 4 = = 10 From the recurrence relation, we can see that this sequence may be given by the formula (for all n >= 1): n-1 Kn = (n – 1) = S i = n(n – 1)/2 i=0

Example 4 Tower of Hanoi The object of the Towers of Hanoi is to move all the disks from the first peg to the third peg while always following these rules: 1. Only one disk may be moved at a time (specifically, the top disk on any peg). 2. At no time can a larger disk be placed on a smaller one.

Hn = (2i * Hn-i) + 2i-1 + 2i-2 + ... + 22 + 21 + 20
The n – 1 disks on the auxiliary peg are moved to the ending peg, requiring an additional Hn-1 moves. This gives us the recurrence relation: Hn = 2Hn-1 + 1 The base case for this relations is H 0 = 0, since if there are no disks, there are no moves required to have “all” the disks on the third peg. To determine a closed form formula where there is no H n on the right side of the equation, we will try repeated substitution: Hn = 2Hn-1 + 1 = 2(2Hn-2 + 1) + 1 = 22 * Hn = 22 (2Hn-3 + 1) = 23 * Hn The pattern to this recurrence relation is: Hn = (2i * Hn-i) + 2i-1 + 2i We can set n = i (this will require an inductive proof): Hn = (2n * H0) + 2n-1 + 2n Substituting H0 = 0, yields the formula: Hn = 2n-1 + 2n

Example 5 Find a closed form solution for the following recurrence relations. For brevity, we omit the inductive proofs. a) Recurrence relation: a0 = 2 an = 3an-1 Solution: an = 3 (3an-2) = 32 an-2 an = 32 (3an-3) = 33 an-3 an = 3i-1 (3an-i) = 3i an-I Set i = n, yielding: an = 3n a0 an = 2 * 3n

b) Recurrence relation: a0 = 1
an = 2an-1 – 1 Solution: an = 2(2an-2 – 1) – 1 = 22 an-2 – 2 – 1 an = 22 (2an-3 – 1) – 2 – 1 = 23 an-3 – 22 – 2 – 1 an = 2i (an-i) – 2i-1 – 2i-2 – … – 20 Set i = n, yielding: an = 2n (a0) – 2n-1 – 2n-2 – … – 20 = 2n – 2n-1 – 2n-2 – … – 20 an = 2n – (2n – 1) (Note: 2n-1 – 2n-2 – … – 1 = 2n – 1) an = 1 c) Recurrence relation: a0 = 5 an = nan-1 an = n(n-1)an-2 an = n(n-1)(n-2)an-3 an = n(n-1)(n-2)…(n-i+1)an-I an = n(n-1)(n-2)…(1) a0 = a0 n! an = 5n!

A recurrence relation expresses the running time of a recursive algorithm. This includes how many recursive calls are generated at each level of the recursion, how much of the problem is solved by each recursive call, and how much work is done at each level.

Example 6 Consider the following function to compute factorials:
int factorial(int n) { 1) if (n <= 1) 2) return(1); else 3) return(n * factorial(n-)); } Recurrence relation: base case: T(1) = a induction: T(n) = b + T(n-1), for n > 1 Closed form formula: T(1) = a T(2) = b + T(1) = b + a T(3) = b + T(2) = b + (b + a) = a + 2b T(4) = b + T(3) = b + (a + 2b) = a + 3b T(n) = a + (n-1)b for all n >= 1

Proof: Let P(n) denote that the running time of factorial is T(n) = a + (n-1)b. And, recall that the recurrence relation definition give us: T(1) = a, and T(n) = b + T(n-1) for n > 1. Base case: prove that P(1) is true T(1) = a + ((1 – 1) * b) = a + (0 * b) = a. This equation holds since the base case of our inductive definition states that T(1) = a. Inductive case: inductive hypothesis is to assume P(k): T(k) = a + (k-1)b, and show P(k+1): T(k+1) = a + kb. We know from the recurrence relation definition that T(k+1) = b + T(k). We use the inductive hypothesis to substitute for T(k). This gives us: T(k+1) = b + T(k) = b + a + (k-1)b = b + a + kb - b = a + kb P(k+1) holds when P(k) holds, and P(1) holds, therefore P(n) is true for all n >= 1.

Example 7 Consider the following recursive selection sort algorithm:
void SelectionSort(int A[], int i, int n) { int j, small, temp; 1) if (i < n) { 2) small = i; 3) for (j = i + 1, j <= n, j++) { 4) if (A[j] < A[small]) small = j; } 6) temp = A[small]; 7) A[small] = A[i]; 8) A[i] = temp; 9) SelectionSort(A, i + 1, n);

The inductive definition of recursive SelectionSort is:
T(1) = a T(m) = T(m-1) + O(m) To solve this recurrence relation, we first get rid of the big-Oh expression by substituting the definition of big-Oh: (f(n) = O(g(n)) if f(n) <= C * g(n)), so we can substitute C*m for O(m): T(m) = T(m-1) + C*m Now, we can either try repeated substitutions or just enumerate a few cases to look for a pattern. Let’s try repeated substitution: T(m) = T(m-1) + C*m = T(m-2) + 2Cm - C because T(m-1) = T(m-2) + C(m-1) = T(m-3) + 3Cm - 3C because T(m-2) = T(m-3) + C(m-2) = T(m-4) + 4Cm - 6C because T(m-3) = T(m-4) + C(m-3) = T(m-5) + 5Cm - 10C because T(m-4) = T(m-5) + C(m-4) ... = T(m-j) + jCm - (j(j-1)/2)C

To get a closed form formula we let j = m – 1
T(m) = T(1) + (m-1)Cm - ((m-1)(m-2)/2)C = a + m2C - Cm - (m2C - 3Cm + 2C)/2 = a + (2m2C - 2Cm - m2C + 3Cm - 2C)/2 = a + (m2C + Cm - 2C)/2 Closed form formula T(m) = a + (m2C + Cm - 2C)/2

Example 8 MergeSort(L) 1) if (length of L > 1) {
2) Split list into first half and second half 3) MergeSort(first half) 4) MergeSort(second half) 5) Merge first half and second half into sorted list }

To analyze the complexity of MergeSort, we need to define a recurrence relation. The base case is when we have a list of 1 element and only line 1 of the function is executed. Thus, the base case is constant time, O(1). If the test of line 1 fails, we must execute lines The time spent in this function when the length of the list > 1 is the sum of the following: 1) O(1) for the test on line 1 2) O(n) for the split function call on line 2 3) T(n/2) for recursive call on line 3 4) T(n/2) for recursive call on line 4 5) O(n) for the merge function call on line 5 If we drop the O(1)'s and apply the summation rule, we get 2T(n/2) + O(n). If we substitute constants in place of the big-Oh notation we obtain: T(1) = a T(n) = 2T(n/2) + bn To solve this recurrence relation, we will enumerate a few values. We will stick to n's that are powers of two so things divide evenly: T(2) = 2T(1) + 2b = a + 2b T(4) = 2T(2) + 4b = 2(2a + 2b) + 4b = 4a + 8b T(8) = 2T(4) + 8b = 2(4a + 8b) + 8b = 8a + 24b T(16) = 2T(8) + 16b = 2(8a + 24b) + 16b = 16a + 64b

There is obviously a pattern but it is not as easy to represent as the others have been. Note the following relationships: value of n: coefficient of b: ratio: So, it appears that the coefficient of b is n times another factor that grows by 1 each time n doubles. The ratio is log2 n because log2 2 = 1, log2 4 = 2, log2 8 = 3, etc. Our "guess" for the solution of this recurrence relation is T(n) = an + bn log2 n. We could have used repeated substitution in which case we would have the following formula: T(n) = 2i T(n/2i) + ibn Now, if we let i = log2 n, we end up with: n*T(1) + bn log2 n = an + bn log2 n (because 2log2n = n).

Theorem 1 (Master Theorem):
Let f be an increasing function that satisfies the recurrence relation: f(n) = a f(n/b) + cnd whenever n = bk, where k is a positive integer, a >= 1, b is an integer greater than 1, c is a positive real number, and d is a non-negative real number. Then: O(nd) if a < bd f(n) = O(nd log n) if a = bd O(n log a) if a > bd

Example 9 Problem: Use Theorem 1 above to find the big-Oh running time of MergeSort (from Example 9). Solution: In Example 9, we are given the recurrence relation for MergeSort as: T(n) = 2T(n/2) + xn where we have simply replaced the positive constant b in the original recurrence relation with the constant x, so that we do not confuse variable names below. Applying Theorem 1, we choose these constants: a = 2, b = 2, c = x, and d = 1 and it becomes: f(n) = 2 f(n/2) + xn1

Consider the three cases of the Master Theorem, which are based on the relationship between a and bd. Here are some examples to consider: 1. a < bd: f(n) = 2 f(n/2) + xn2. In this example, 2 < 22, and thus f(n) = O(n2). The xn2 term is growing faster than the 2 f(n/2) and thus dominates. 2. a = bd: f(n) = 2 f(n/2) + xn1. In this example, 2 = 2, and thus f(n) = O(n log n). The two terms grow together. 3. a > bd: f(n) = 8 f(n/2) + xn2. In this example, 8 < 22, and thus f(n) = O(nlog 8) = O(n3). The 8 f(n/2) term is growing faster than the xn2 and thus dominates.

Example 10 Problem: Use repeated substitution to find the time complexity of the function recurse. Verify your result using induction. /* Assume only non-negative even values of n are passed in */ void recurse(int n) { int i, total = 0; 1) if (n == 0) return 1; 2) for (i = 0; i < 4; i++) { 3) total += recurse(n-2); } 4) return total; Solution: When n = 0 (the base case), this function only executes line 1, doing O(1) work. We will note this constant amount of work as a. When n >= 2 (the recursive case), this function does O(1) work in executing lines 1, 2, and 4, which we will denote by b, and also makes four recursive calls with parameter values n-2 in the body loop (line 3).

We use these two points to perform the recurrence relation analysis below:
From the base case, we have: T0 = a From the recursive case, we have: Tn = 4Tn-2+ b We apply repeated substitution: T n = 4Tn-2 + b T n = 4(4Tn-4 + b) + b = 42 Tn-4 + 4b + b T n = 42 (4Tn-6 + b) + 4b + b = 43 Tn b + 4b + b T n = 4i Tn-2i + 4i-1 b + 4i-2 b + … + 40 b Note that 4k = 22k, yielding: Tn = 22i Tn-2i + 22(i-1) b + 2 2(i-2) b + … + 20 b Set i = n/2, yielding: Tn = 2n T0 + 2n-2 b + 2n-4 b + … + 20 b = 2n a + (2n-2 + 2n-4 + … + 20) b

We need to compute the closed form for (2n-2 + 2n-4 + … + 20) = (2n – 1)/3.
Here is a brief digression on how we compute this closed form formula: Let x = (2n-2 + 2n-4 + … + 20) So, 22 x = 4x = 22 (2n-2 + 2n-4 + … + 20) = (2n + 2n-2 + … + 22) 22 x – x = 3x = (2n + 2n-2 + … + 22) – (2n-2 + 2n-4 + … + 20) 3x = 2n – 20 = 2n – 1 x = (2n – 1)/3 = (2n-2 + 2n-4 + … + 20)

Base case: Show P(0).T0 = 20 a + ((20 – 1)/3) b = a + ((1 – 1)/3) b = a. This is the initial condition. Inductive case: Assume inductive hypothesis P(n): Tn = 2n a + ((2n – 1)/3) b Show P(n+2): Tn+2 = 2n+2 a + ((2n+2 – 1)/3) b Note: only consider even values of n Tn+2 = 4Tn + b by definition of the recurrence Tn+2 = 4(2n a + ((2n – 1)/3) b) + b substituting T n with the inductive hypothesis Tn+2 = 22 (2n a + ((2n – 1)/3) b) + b algebra: 4 = 22 Tn+2 = 2n+2 a + ((2n+2 – 22)/3) b + b algebra: multiply in the 22 Tn+2 = 2n+2 a + ((2n+2 – 3 – 1)/3) b + b algebra: -22 = Tn+2 = 2n+2 a + ((2n+2 – 1)/3) b – b + b algebra: (-3/3)b = -b Tn+2 = 2n+2 a + ((2n+2 – 1)/3) b this is the desired result QED. We calculate the big-Oh complexity for the function, as follows: From the recurrence relation Tn = 2n a + ((2n – 1)/3) b, we see that the algorithm has time complexity: O(2n a) + O(2n b) = O(2n) + O(2n) = O(2n).