Chapter 5: Recursion

Similar documents
Chapter 5: Recursion. Objectives

Chapter 5: Recursion


Identify recursive algorithms Write simple recursive algorithms Understand recursive function calling

6.001 Notes: Section 4.1

Recursion. What is Recursion? Simple Example. Repeatedly Reduce the Problem Into Smaller Problems to Solve the Big Problem

Recursion(int day){return Recursion(day += 1);} Comp Sci 1575 Data Structures. Recursive design. Convert loops to recursion

(Refer Slide Time: 00:51)

Recursive Definitions

CMSC 132: Object-Oriented Programming II. Recursive Algorithms. Department of Computer Science University of Maryland, College Park

School of Informatics, University of Edinburgh

Violations of the contract are exceptions, and are usually handled by special language constructs. Design by contract

Data structure and algorithm in Python

Recursive Search with Backtracking

Week - 03 Lecture - 18 Recursion. For the last lecture of this week, we will look at recursive functions. (Refer Slide Time: 00:05)

8. Functions (II) Control Structures: Arguments passed by value and by reference int x=5, y=3, z; z = addition ( x, y );

CS 151. Recursion (Review!) Wednesday, September 19, 12

Lecture 1 Contracts : Principles of Imperative Computation (Fall 2018) Frank Pfenning

CSCE150A. Introduction. While Loop. Compound Assignment. For Loop. Loop Design. Nested Loops. Do-While Loop. Programming Tips CSCE150A.

Computer Science & Engineering 150A Problem Solving Using Computers. Chapter 5. Repetition in Programs. Notes. Notes. Notes. Lecture 05 - Loops

Recursion vs Induction

Design and Analysis of Algorithms Prof. Madhavan Mukund Chennai Mathematical Institute. Module 02 Lecture - 45 Memoization

Data Structures And Algorithms

Recursion. Recursion is: Recursion splits a problem:

CSC 273 Data Structures

Lecture 1 Contracts. 1 A Mysterious Program : Principles of Imperative Computation (Spring 2018) Frank Pfenning

Functions. CS10001: Programming & Data Structures. Sudeshna Sarkar Professor, Dept. of Computer Sc. & Engg., Indian Institute of Technology Kharagpur

Fundamentals of Programming Session 13

DM502 Programming A. Peter Schneider-Kamp.

Practice Problems for the Final

Wentworth Institute of Technology COMP1050 Computer Science II Spring 2017 Derbinsky. Recursion. Lecture 13. Recursion

Two Approaches to Algorithms An Example (1) Iteration (2) Recursion

Lecture 10: Recursion vs Iteration

The Art of Recursion: Problem Set 10

Recursion CS GMU

Lecture 10: Recursive Functions. Computer System and programming in C 1

Backtracking. See Section 7.7 p of Weiss

Chapter Fourteen Bonus Lessons: Algorithms and Efficiency

Agenda. The worst algorithm in the history of humanity. Asymptotic notations: Big-O, Big-Omega, Theta. An iterative solution

Dr. Chuck Cartledge. 15 July 2015

Lesson 12: Recursion, Complexity, Searching and Sorting. Modifications By Mr. Dave Clausen Updated for Java 1_5

Emil Sekerinski, McMaster University, Winter Term 16/17 COMP SCI 1MD3 Introduction to Programming

CS 310 Advanced Data Structures and Algorithms


Algorithm Design and Recursion. Search and Sort Algorithms

Recursion vs Induction. CS3330: Algorithms The University of Iowa

Recursion. Chapter 7

Recursion. Fundamentals of Computer Science

! Addition! Multiplication! Bigger Example - RSA cryptography

DESIGN AND ANALYSIS OF ALGORITHMS. Unit 1 Chapter 4 ITERATIVE ALGORITHM DESIGN ISSUES

Tail Recursion. ;; a recursive program for factorial (define fact (lambda (m) ;; m is non-negative (if (= m 0) 1 (* m (fact (- m 1))))))

Lecture Notes on Dynamic Programming

P1 Engineering Computation

APCS-AB: Java. Recursion in Java December 12, week14 1

More Complicated Recursion CMPSC 122

Discussion on Writing of Recursive Algorithm

Reading 8 : Recursion

Fundamentals of Recursion. Solving Problems Recursively. Recursive example. Recursive example

Recursion CSCI 136: Fundamentals of Computer Science II Keith Vertanen Copyright 2011

RECURSION. Many Slides from Ken Birman, Cornell University

Unit 1 Chapter 4 ITERATIVE ALGORITHM DESIGN ISSUES

Recursion Chapter 4 Self-Reference. Recursive Definitions Inductive Proofs Implementing Recursion

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Recursion. Overview. Mathematical induction. Hello recursion. Recursion. Example applications. Goal: Compute factorial N! = 1 * 2 * 3...

Recursion. So, just as you are allowed to call function B from within function A, you are ALSO allowed to call function A from within function A!

Reading Assignment. Lazy Evaluation

OVERVIEW. Recursion is an algorithmic technique where a function calls itself directly or indirectly. Why learn recursion?

6.001 Notes: Section 15.1

Chapter 1. Math review. 1.1 Some sets

142

DM536 / DM550 Part 1 Introduction to Programming. Peter Schneider-Kamp.

DM550/DM857 Introduction to Programming. Peter Schneider-Kamp

Shared-memory Parallel Programming with Cilk Plus

C Functions. Object created and destroyed within its block auto: default for local variables

P Is Not Equal to NP. ScholarlyCommons. University of Pennsylvania. Jon Freeman University of Pennsylvania. October 1989

CS159. Nathan Sprague. November 9, 2015

CS450 - Structure of Higher Level Languages

Implementing Coroutines with call/cc. Producer/Consumer using Coroutines

Recursion & Performance. Recursion. Recursion. Recursion. Where Recursion Shines. Breaking a Problem Down

Homework. Reading: Chapter 17 Homework: All exercises from Chapter 17 Due: 10/27 Correction: Chapter 16 homework is due 10/25

Outline. Introduction. 2 Proof of Correctness. 3 Final Notes. Precondition P 1 : Inputs include

In this chapter you ll learn:

Functions. Computer System and programming in C Prentice Hall, Inc. All rights reserved.

19 Much that I bound, I could not free; Much that I freed returned to me. Lee Wilson Dodd

DM536 Introduction to Programming. Peter Schneider-Kamp.

AXIOMS FOR THE INTEGERS

CS112 Lecture: Repetition Statements

STUDENT LESSON A9 Recursion

Lecture Notes on Arrays

EE 368. Weeks 4 (Notes)

The Knapsack Problem an Introduction to Dynamic Programming. Slides based on Kevin Wayne / Pearson-Addison Wesley

CSC 148 Lecture 3. Dynamic Typing, Scoping, and Namespaces. Recursion

Reading: Chapter 17 Homework: All exercises from Chapter 17 Due: 10/27 Correction: Chapter 16 homework is due 10/25

Decision-Making and Repetition

RECURSION AND LINKED LISTS 3

What is Iteration? CMPT-101. Recursion. Understanding Recursion. The Function Header and Documentation. Recursively Adding Numbers

Theoretical Computer Science

CS112 Lecture: Loops

Chapter 1 Programming: A General Overview

Print words entered, but backwards. Solving Problems Recursively. Faster exponentiation. Exponentiation

Transcription:

Chapter 5: Recursion

Objectives Looking ahead in this chapter, we ll consider Recursive Definitions Function Calls and Recursive Implementation Anatomy of a Recursive Call Tail Recursion Nontail Recursion Indirect Recursion Nested Recursion Excessive Recursion Backtracking Data Structures and Algorithms in C++, Fourth Edition 2

Recursive Definitions It is a basic rule in defining new ideas that they not be defined circularly However, it turns out that many programming constructs are defined in terms of themselves Fortunately, the formal basis for these definitions is such that no violations of the rules occurs These definitions are called recursive definitions and are often used to define infinite sets This is because an exhaustive enumeration of such a set is impossible, so some others means to define it is needed Data Structures and Algorithms in C++, Fourth Edition 3

Recursive Definitions (continued) There are two parts to a recursive definition The anchor or ground case (also sometimes called the base case) which establishes the basis for all the other elements of the set The inductive clause which establishes rules for the creation of new elements in the set Using this, we can define the set of natural numbers as follows: 1. 0 ε N (anchor) 2. if n ε N, then (n + 1) ε N (inductive clause) 3. there are no other objects in the set N There may be other definitions; an alternative to the previous definition is shown on page 170 Data Structures and Algorithms in C++, Fourth Edition 4

Recursive Definitions (continued) We can use recursive definitions in two ways: To define new elements in the set in question To demonstrate that a particular item belongs in a set Generally, the second use is demonstrated by repeated application of the inductive clause until the problem is reduced to the base case This is often the case when we want to define functions and sequences of numbers However this can have undesirable consequences For example, to determine 3! (3 factorial) using a recursive definition, we have to work back to 0! Data Structures and Algorithms in C++, Fourth Edition 5

Recursive Definitions (continued) This results from the recursive definition of the factorial function: 1 if n 0 n! n n 1! if n 0 So 3! = 3 2! = 3 2 1! = 3 2 1 0! = 3 2 1 1 = 6 This is cumbersome and computationally inefficient It would be helpful to find a formula that is equivalent to the recursive one without referring to previous values n For factorials, we can use n! i i 1 In general, however, this is frequently non-trivial and often quite difficult to achieve Data Structures and Algorithms in C++, Fourth Edition 6

Recursive Definitions (continued) These discussions and examples have been on a theoretical basis From the standpoint of computer science, recursion occurs frequently in language definitions as well as programming Fortunately, the translation from specification to code is fairly straightforward; consider a factorial function in C++: unsigned int factorial (unsigned int n){ } if (n == 0) return 1; else return n * factorial (n 1); Data Structures and Algorithms in C++, Fourth Edition 7

Recursive Definitions (continued) Although the code is simple, the underlying ideas supporting its operation are quite involved Fortunately, most modern programming languages incorporate mechanisms to support the use of recursion, making it transparent to the user Typically, recursion is supported through use of the runtime stack So to get a clearer understanding of recursion, we will look at how function calls are processed Data Structures and Algorithms in C++, Fourth Edition 8

Anatomy of a Recursive Call To gain further insight into the behavior of recursion, let s dissect a recursive function and analyze its behavior The function we will look at is defined in the text, and can be used to raise a number x to a non-negative integer power n: x n 1 if n 0 n 1 x x if n 0 We can also represent this function using C++ code, shown on the next slide Data Structures and Algorithms in C++, Fourth Edition 9

Anatomy of a Recursive Call (continued) /* 102 */ double power (double x, unsigned int n) { /* 103 */ if (n == 0) /* 104 */ return 1.0; else /* 105 */ return x * power(x,n-1); } Using the definition, the calculation of x 4 would be calculated as follows: x 4 = x x 3 = x (x x 2 ) = x (x (x x 1 )) = x (x (x (x x 0 ))) = x (x (x (x 1))) = x (x (x (x))) = x (x (x x)) = x (x x x) = x x x x Notice how repeated application of the inductive step leads to the anchor Data Structures and Algorithms in C++, Fourth Edition 10

Anatomy of a Recursive Call (continued) This produces the result of x 0, which is 1, and returns this value to the previous call That call, which had been suspended, then resumes to calculate x 1, producing x Each succeeding return then takes the previous result and uses it in turn to produce the final result The sequence of recursive calls and returns looks like: call 1 x 4 = x x 3 = x x x x call 2 x 3 = x x 2 = x x x call 3 x 2 = x x 1 = x x call 4 x 1 = x x 0 = x 1 call 5 x 0 = 1 Data Structures and Algorithms in C++, Fourth Edition 11

Anatomy of a Recursive Call (continued) Now, the sequence of calls is kept track of on the runtime stack, which stores the return address of the function call This is used to remember where to resume execution after the function has completed The function power()in the earlier slide is called by the following statement: /* 136 */ y = power(5.6,2); The sequence of calls and returns generated by this call, along with the address of the calling statement, the return address, and the arguments, are shown in Figure 5.2 Data Structures and Algorithms in C++, Fourth Edition 12

Recursion - rules Rule 1: Provide exit from recursion. (focus on base cases some times, more than one base case is needed.) Rule 2: Make sure that the successive recursive calls progress towards the base case. Rule 3: Assume that recursive calls work. Rule 4: Compound interest rule: Avoid redundant calls.

Recursion simple examples 1) Compute n! n! = 1 x 2 x n = (n 1)! x n 2) Compute 1 + 2 + + n f(n) = n + f(n 1) 3) Compute the n-th Fibonacci number f(n) = f(n 1) + f(n 2)

A faster way to compute x n Given x and n, we want to compute x n. Obvious iterative solution: int exp_it(int x, int n) { int temp = x; for (int j= 1; j < n; ++j) temp*= x; return temp; } The number of multiplications performed is n 1. We will see that a recursive algorithm provides a much faster solution. Faster algorithm is crucial for RSA encryption algorithm.

Idea behind the algorithm Rule of exponents: x n = (x 2 ) n/2 if n is even x * (x 2 ) (n-1)/2 if n is odd base case n = 1 return x even n call exp(x*x, n/2) and return the result. odd n call exp(x*x, (n 1)/2) and multiply the result of call by x and return the product. In this example, recursion makes algorithm faster

Remove negative items from the list Example: List: -3, 4, 5, -2, 11 becomes 4, 5, 11 We will write this one recursively.

Remove negative items from the list Example: List: -3, 4, 5, -2, 11 becomes 4, 5, 11 We will write this one recursively. void remove_negative() { // removes all the negative items from a list // Example input: -4 5 6-2 8; output: 5 6 8 if (head == NULL) return; else if (head->key >= 0) { List nlist = List(head->next); nlist.remove_negative(); head->next = nlist.head; } else { List nlist = List(head->next); nlist.remove_negative(); head = nlist.head; } }

Excessive Recursion Recursive algorithms tend to exhibit simplicity in their implementation and are typically easy to read and follow However, this straightforwardness does have some drawbacks Generally, as the number of function calls increases, a program suffers from some performance decrease Also, the amount of stack space required increases dramatically with the amount of recursion that occurs This can lead to program crashes if the stack runs out of memory More frequently, though, is the increased execution time leading to poor program performance Data Structures and Algorithms in C++, Fourth Edition 19

Excessive Recursion (continued) As an example of this, consider the Fibonacci numbers They are first mentioned in connection with Sanskrit poetry as far back as 200 BCE Leonardo Pisano Bigollo (also known as Fibonacci), introduced them to the western world in his book Liber Abaci in 1202 CE The first few terms of the sequence are 0, 1, 1, 2, 3, 5, 8, and can be generated using the function: n Fib( n) Fib n Fib n if n 2 2 1 otherwise Data Structures and Algorithms in C++, Fourth Edition 20

Excessive Recursion (continued) This tells us that that any Fibonacci number after the first two (0 and 1) is defined as the sum of the two previous numbers However, as we move further on in the sequence, the amount of calculation necessary to generate successive terms becomes excessive This is because every calculation ultimately has to rely on the base case for computing the values, since no intermediate values are remembered The following algorithm implements this definition; again, notice the simplicity of the code that belies the underlying inefficiency Data Structures and Algorithms in C++, Fourth Edition 21

Excessive Recursion (continued) unsigned long Fib(unsigned long n) { if (n < 2) // else } return n; return Fib(n-2) + Fib(n-1); If we use this to compute Fib(6)(which is 8), the algorithm starts by calculating Fib(4) + Fib(5) The algorithm then needs to calculate Fib(4) = Fib(2) + Fib(3), and finally the first term of that is Fib(2) = Fib(0) + Fib(1)= 0 + 1 = 1 Data Structures and Algorithms in C++, Fourth Edition 22

Excessive Recursion (continued) The entire process can be represented using a tree to show the calculations: Fig. 5.8 The tree of calls for Fib(6). Counting the branches, it takes 25 calls to Fib() to calculate Fib(6) Data Structures and Algorithms in C++, Fourth Edition 23

Excessive Recursion (continued) The total number of additions required to calculate the n th number can be shown to be Fib(n + 1) 1 With two calls per addition, and the first call taken into account, the total number of calls is 2 Fib(n + 1) 1 Values of this are shown in the following table: Fig. 5.9 Number of addition operations and number of recursive calls to calculate Fibonacci numbers. Data Structures and Algorithms in C++, Fourth Edition 24

Backtracking Backtracking is an approach to problem solving that uses a systematic search among possible pathways to a solution As each path is examined, if it is determined the pathway isn t viable, it is discarded and the algorithm returns to the prior branch so that a different path can be explored Thus, the algorithm must be able to return to the previous position, and ensure that all pathways are examined Backtracking is used in a number of applications, including artificial intelligence, compiling, and optimization problems One classic application of this technique is known as The Eight Queens Problem Data Structures and Algorithms in C++, Fourth Edition 25

Backtracking (continued) In this problem, we try to place eight queens on a chessboard in such a way that no two queens attack each other Fig. 5.11 The eight queens problem Data Structures and Algorithms in C++, Fourth Edition 26

Backtracking (continued) The approach to solving this is to place one queen at a time, trying to make sure that the queens do not check each other If at any point a queen cannot be successfully placed, the algorithm backtracks to the placement of the previous queen This is then moved and the next queen is tried again If no successful arrangement is found, the algorithm backtracks further, adjusting the previous queen s predecessor, etc. A pseudocode representation of the backtracking algorithm is shown in the next slide; the process is described in detail on pages 192 197, along with a C++ implementation Data Structures and Algorithms in C++, Fourth Edition 27

Backtracking (continued) putqueen(row) for every position col on the same row if position col is available place the next queen in position col; if (row < 8) putqueen(row+1); else success; remove the queen from position col; This algorithm will find all solutions, although some are symmetrical Data Structures and Algorithms in C++, Fourth Edition 28

Concluding Remarks The foregoing discussion has provided us with some insight into the use of recursion as a programming tool While there are no specific rules that require we use or avoid recursion in any particular situation, we can develop some general guidelines For example, recursion is generally less efficient than the iterative equivalent However, if the difference in execution times is fairly small, other factors such as clarity, simplicity, and readability may be taken into account Recursion often is more faithful to the algorithm s logic Data Structures and Algorithms in C++, Fourth Edition 29

Concluding Remarks (continued) The task of converting recursive algorithms into their iterative equivalents can often be difficult to perform As we saw with nontail recursion, we frequently have to explicitly implement stack handling to handle the runtime stack processing incorporated into the recursive form Again, this may require analysis and judgment by the programmer to determine the best course of action The text suggests a couple of situations where iterative versions are preferable to recursive ones First, real-time systems, with their stringent time requirements, benefit by the faster response of iterative code Data Structures and Algorithms in C++, Fourth Edition 30

Concluding Remarks (continued) Another situation occurs in programs that are repeatedly executed, such as compilers However, even these cases may be changed if the hardware or operating environment of the algorithm supports processing that speeds the recursive algorithm (consider a hardware supported stack) Sometimes the best way to decide which version to use relies simply on coding both forms and testing them This is especially true in cases involving tail recursion, where the recursive version may be faster, and with nontail recursion where use a stack cannot be eliminated Data Structures and Algorithms in C++, Fourth Edition 31

Concluding Remarks (continued) One place where recursion must be examined carefully is when excessive, repeated calculations occur to obtain results The discussion of the Fibonacci sequence illustrated this concern Often, drawing a call tree such as figure 5.8 can be helpful Trees with a large number of levels can threaten stack overflow problems On the other hand, shallow, bushy trees may indicate a suitable recursive candidate, provided the number of repetitions is reasonable Data Structures and Algorithms in C++, Fourth Edition 32