However it is strongly believed that NP and co NP are different For instance no

# However it is strongly believed that np and co np are

This preview shows page 165 - 168 out of 244 pages.

However, it is (strongly) believed that NP and co-NP are different. For instance, no polynomial solution to the problem of factoring numbers was found, and this problem is in both NP and co-NP . 8.2 Recursion The three laws of recursion are: 1. A recursive algorithm must have a base case . 2. A recursive algorithm must change its state and move toward the base case. 3. A recursive algorithm must call itself, recursively. For every recursive call, the recursive function has to allocate memory on the stack for arguments, return address, and local variables, costing time to push and pop these data onto the stack. Recursive algorithms take at least O ( n ) space where n is the depth of the recursive call. Recursion is very costly when there are duplicated calculations and/or there are overlap among subproblems. In some cases this can cause the stack
166 CHAPTER 8. ASYMPTOTIC ANALYSIS to overflow. For this reason, where subproblems overlap, iterative solutions might be a better approach. For example, in the case of the Fibonacci series, the iterative solution runs on O ( n ) while the recursive solution runs on exponential runtime. Recursive Relations To describe the running time of recursive functions, we use recursive relations: T ( n ) = a · T ( g ( n )) + f ( n ) , where a represents the number of recursive calls, g ( n ) is the size of each subproblem to be solved recursively, and f ( n ) is any extra work done in the function. The following table shows examples of recursive relations: T ( n ) = T ( n - 1) + 1 O ( n ) Processing a sequence T ( n ) = T ( n - 1) + n O ( n 2 ) Handshake problem T ( n ) = 2 T ( n - 1) + 1 O (2 n ) Towers of Hanoi T ( n ) = T ( n/ 2) + 1 O (ln n ) Binary search T ( n ) = T ( n/ 2) + n O ( n ) Randomized select T ( n ) = 2 T ( n/ 2) + 1 O ( n ) Tree transversal T ( n ) = 2 T ( n/ 2) + n O ( n ln n ) Sort by divide and conquer Divide and Conquer Algorithms Recurrences for the divide and conquer algorithms have the form: T ( n ) = a · T ( n/b ) + f ( n ) , where we have a recursive calls, each with a percentage 1 /b of the dataset. Summing to this, the algorithm does f ( n ) of work. To reach the problem of T(1) = 1 in the final instance (leaf, as we will learn when we study trees), the height is defined as h = ln b n , Fig. 8.2. 8.3 Runtime in Functions We are now ready to estimate algorithm runtimes. First of all, if the algo- rithm does not have any recursive calling, we only need to analyse its data
8.3. RUNTIME IN FUNCTIONS 167 Figure 8.2: Tree illustrating divide and conquer recurrences. structures and flow blocks. In this case, complexities of code blocks exe- cuted one after the other are just added and complexities of nested loops are multiplied. If the algorithm has recursive calls, we can use the recursive functions from the previous section to find the runtime. When we write a recurrence relation for a function, we must write two equations, one for the general case and one for the base case (that should be O (1), so that T (1) = 1). Keeping this in mind, let us take a look at the example of the algorithm to find the n th element in a Fibonacci sequence, which is known as to be exponential: [general_poroblems/numbers/find_fibonacci_seq.py] def find_fibonacci_seq_rec(n): if

#### You've reached the end of your free preview.

Want to read all 244 pages?

Stuck? We have tutors online 24/7 who can help you get unstuck.
Ask Expert Tutors You can ask You can ask You can ask (will expire )
Answers in as fast as 15 minutes