Lecture 11 Recursive Thinking CSC212 Data Structure

Slides:



Advertisements
Similar presentations
Chapter 8 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences of a problem.
Advertisements

Slides prepared by Rose Williams, Binghamton University Chapter 11 Recursion.
Recursion. Objectives At the conclusion of this lesson, students should be able to Explain what recursion is Design and write functions that use recursion.
Slides prepared by Rose Williams, Binghamton University Chapter 11 Recursion.
1 Chapter 18 Recursion Dale/Weems/Headington. 2 Chapter 18 Topics l Meaning of Recursion l Base Case and General Case in Recursive Function Definitions.
Chapter 11 Recursion Copyright © 2010 Pearson Addison-Wesley. All rights reserved.
 Chapter 9 introduces the technique of recursive programming.  As you have seen, recursive programming involves spotting smaller occurrences of a problem.
Copyright © 2003 Pearson Education, Inc. Slide 1.
1 Chapter 7 Recursion. 2 What Is Recursion? l Recursive call A method call in which the method being called is the same as the one making the call l Direct.
1 C++ Plus Data Structures Nell Dale Chapter 7 Programming with Recursion Slides by Sylvia Sorkin, Community College of Baltimore County - Essex Campus.
20-1 Computing Fundamentals with C++ Object-Oriented Programming and Design, 2nd Edition Rick Mercer Franklin, Beedle & Associates, 1999 ISBN
Iteration. Adding CDs to Vic Stack In many of the programs you write, you would like to have a CD on the stack before the program runs. To do this, you.
Lecturer: Dr. AJ Bieszczad Chapter 11 COMP 150: Introduction to Object-Oriented Programming 11-1 l Basics of Recursion l Programming with Recursion Recursion.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
Slides prepared by Rose Williams, Binghamton University ICS201 Lecture 19 : Recursion King Fahd University of Petroleum & Minerals College of Computer.
1 Programming with Recursion Slides by Sylvia Sorkin, Community College of Baltimore County - Essex Campus and Robert Moyer, Montgomery County Community.
1 Chapter 13 Recursion. 2 Chapter 13 Topics l Meaning of Recursion l Base Case and General Case in Recursive Function Definitions l Writing Recursive.
Recursion Textbook chapter Recursive Function Call a recursive call is a function call in which the called function is the same as the one making.
Computer Science and Software Engineering University of Wisconsin - Platteville 9. Recursion Yan Shi CS/SE 2630 Lecture Notes Partially adopted from C++
224 3/30/98 CSE 143 Recursion [Sections 6.1, ]
Computer Science Department Data Structure & Algorithms Lecture 8 Recursion.
Chapter 13 Recursion. Learning Objectives Recursive void Functions – Tracing recursive calls – Infinite recursion, overflows Recursive Functions that.
Chapter 13 Recursion. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. Slide 2 Overview Recursive Functions for Tasks(13.1) Recursive Functions.
Copyright © 2012 Pearson Addison-Wesley. All rights reserved. Chapter 14 Recursion.
CSIS 123A Lecture 9 Recursion Glenn Stevenson CSIS 113A MSJC.
CSC211 Data Structures Lecture 13 Recursive Thinking Instructor: Prof. Xiaoyan Li Department of Computer Science Mount Holyoke College.
Recursion Unit 15. Recursion: Recursion is defined as the process of a subprogram calling itself as part of the solution to a problem. It is a problem.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
1 Recursion. 2 Chapter 15 Topics  Meaning of Recursion  Base Case and General Case in Recursive Function Definitions  Writing Recursive Functions with.
CSC212 Data Structure - Section AB Lecture 13 Recursive Thinking Instructor: Edgardo Molina Department of Computer Science City College of New York.
© Janice Regan, CMPT 128, February CMPT 128: Introduction to Computing Science for Engineering Students Recursion.
Chapter 7 Programming with Recursion. What Is Recursion? Recursive call A method call in which the method being called is the same as the one.
Searching CSE 103 Lecture 20 Wednesday, October 16, 2002 prepared by Doug Hogan.
Copyright © 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Chapter 14 Recursion.
Recursion. Objectives At the conclusion of this lesson, students should be able to Explain what recursion is Design and write functions that use recursion.
Function Recursion to understand recursion you must understand recursion.
CSC 143 P 1 CSC 143 Recursion [Chapter 5]. CSC 143 P 2 Recursion  A recursive definition is one which is defined in terms of itself  Example:  Compound.
Recursion CS 244 Brent M. Dingle, Ph.D. Game Design and Development Program Department of Mathematics, Statistics, and Computer Science University of Wisconsin.
Recursion Powerful Tool
Programming with Recursion
CMSC201 Computer Science I for Majors Lecture 19 – Recursion
Chapter 13 Recursion Copyright © 2016 Pearson, Inc. All rights reserved.
Recursion Version 1.0.
to understand recursion you must understand recursion
User-Written Functions
Linked Lists in Action Chapter 5 introduces the often-used data public classure of linked lists. This presentation shows how to implement the most common.
To understand recursion, you have to understand recursion!
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Stack Data Structure, Reverse Polish Notation, Homework 7
Chapter 14 Recursion. Chapter 14 Recursion Overview 14.1 Recursive Functions for Tasks 14.2 Recursive Functions for Values 14.3 Thinking Recursively.
Using a Stack Chapter 6 introduces the stack data type.
Programming with Recursion
Sentinel logic, flags, break Taken from notes by Dr. Neil Moore
to understand recursion you must understand recursion
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Recursive Thinking Chapter 8 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Using a Stack Chapter 6 introduces the stack data type.
Recursion This slide set was compiled from the Absolute Java textbook slides (Walter Savitch) and the instructor’s class materials.
File I/O in C Lecture 7 Narrator: Lecture 7: File I/O in C.
Hash Tables Chapter 12 discusses several ways of storing information in an array, and later searching for the information. Hash tables are a common.
Algorithm and Ambiguity
Using a Stack Chapter 6 introduces the stack data type.
Basics of Recursion Programming with Recursion
Using a Stack Chapter 6 introduces the stack data type.
Recursion Taken from notes by Dr. Neil Moore
Hash Tables Chapter 12 discusses several ways of storing information in an array, and later searching for the information. Hash tables are a common.
Yan Shi CS/SE 2630 Lecture Notes
Chapter 18 Recursion.
Chapter 13 Recursion Copyright © 2010 Pearson Addison-Wesley. All rights reserved.
Presentation transcript:

Lecture 11 Recursive Thinking CSC212 Data Structure Instructor: George Wolberg Department of Computer Science City College of New York

Outline of This Lecture Start with an Example of Recursion “racing car” – not in the textbook using slides (provided by the authors) Recursive Thinking: General Form Tracing Recursive Calls using blackboard to show the concepts A Closer Look at Recursion activation record and runtime stack

Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences of a problem within the problem itself. This presentation gives an additional example, which is not in the book. This lecture demonstrates a typical pattern that arises in recursive functions. The lecture can be given shortly before or shortly after the students have read Section 9.1. By the way, the book delays the introduction of recursion until just before trees. Our reasoning here is that recursive functions with linked lists can sometimes be bad programming practice because the run-time stack must grow to the length of the linked list (and iterative algorithms are usually just as easy). On the other hand, the depth of recursive tree algorithms is merely the depth of the tree (and equivalent iterative algorithms can be harder to program). Data Structures and Other Objects Using C++

A Car Object To start the example, think about your favorite family car In this lecture, we're going to design a recursive function which manipulates a new object called a Car. In order to explain the Car that I have in mind, think about your favorite family car... NOTE: In Powerpoint, the next few slides will automatically appear every few seconds...

A Car Object To start the example, think about your favorite family car ...let's try for something a bit more modern that this...

A Car Object To start the example, think about your favorite family car ...no, that's too conservative...

A Car Object To start the example, think about your favorite family car ...that's better!

A Car Object To start the example, think about your favorite family car Imagine that the car is controlled by a radio signal from a computer I want you to imagine that this family car is being controlled by a radio signal coming from your computer.

A Car Class To start the example, think about your favorite family car Imagine that the car is controlled by a radio signal from a computer The radio signals are generated by activating member functions of a Car object class Car { public: . . . }; The radio signals themselves are generated by writing a program which uses a new object type called a Car. Each time one of the car methods is activated, the computer sends a radio signal to control the car. This may seem a bit far-fetched, but such radio-controlled hardware really does exist, and the hardware is controlled by programs which could have objects such as these. A similar example is an automatic baggage system at an airport, which is controlled by a computer. Also, remember that in order to understand this example, you don't need to know all the details of how the Car's methods work. All you need to know is what each of the Car's methods accomplishes. I have four particular methods in mind, and I'll describe what each method does.

Member Functions for the Car Class class Car { public: Car(int car_number); void move( ); void turn_around( ); bool is_blocked( ); private: { We don't need to know the private fields! } . . . }; Here are the prototypes of the four member functions. Let's look at each method in turn...

The Constructor When we declare a Car and activate the constructor, the computer makes a radio link with a car that has a particular number. int main( ) { Car racer(7); . . . This example demonstrates the usage of the constructor. In this example, we have declared a Car called racer and the activated the constructor with the argument 7. The argument 7 just indicates which of several cars we want to control. Each car needs to have a unique number. In this example, we are making a radio connection to "Car Number 7". Any future radio signals generated by activating racer's methods will control "Car Number 7".

The turn_around Function When we activate turn_around, the computer signals the car to turn 180 degrees. int main( ) { Car racer(7); racer.turn_around( ); . . . After the connection is made, we can activate other member functions of racer. In this example, we are activating racer.turn_around( ); The function sends a radio signal to the car, telling it to turn 180 degrees. (In case you hadn't noticed, the car has a very small turning radius!)

The turn_around Function When we activate turn_around, the computer signals the car to turn 180 degrees. int main( ) { Car racer(7); racer.turn_around( ); . . . After the connection is made, we can activate other member functions of racer. In this example, we are activating racer.turn_around( ); The function sends a radio signal to the car, telling it to turn 180 degrees. (In case you hadn't noticed, the car has a very small turning radius!)

The move Function When we activate move, the computer signals the car to move forward one foot. int main( ) { Car racer(7); racer.turn_around( ); racer.move( ); . . . Here's an example of the third Car member function in action. When we activate racer.move( ); the result is a radio signal which tells the car to move forward one foot. NOTE: In Powerpoint, the next slide automatically appears, moving the car forward "one foot".

The move Function When we activate move, the computer signals the car to move forward one foot. int main( ) { Car racer(7); racer.turn_around( ); racer.move( ); . . . As you can see, the car has moved forward by a foot.

The is_blocked( ) Function The is_blocked member function detects barriers. int main( ) { Car racer(7); racer.turn_around( ); racer.move( ); if (racer.is_blocked( ) ) cout << "Cannot move!"; . . . The last Car member function is a boolean function called is_blocked. The function returns true if there is some barrier in front of the car, making it impossible to move. The function returns false if the front of the car is unblocked, making a move possible. A question: What will racer.is_blocked return in this example? Answer: True, because there is a definite barrier in front of the car. Another question: Can you state a good precondition for the move member function? Answer: is_blocked must return false.

Your Mission Write a function which will move a Car forward until it reaches a barrier... Now we can examine the problem that I have in mind. I want to write a function which will move a Car forward until it reaches a barrier...

Your Mission Write a function which will move a Car forward until it reaches a barrier... ...as shown here. NOTE: In Powerpoint, this slide automatically appears after six seconds. Each of the next few slides automatically appears after a few more seconds.

Your Mission Write a function which will move a Car forward until it reaches a barrier... Here, you can see that the barrier has been reached. But that is not the end of the function’s work. The function must next...

Your Mission Write a function which will move a Car forward until it reaches a barrier... ...then the car is turned around... ...turn the car around...

Your Mission Write a function which will move a Car forward until it reaches a barrier... ...then the car is turned around... ...and returned to its original location, facing the opposite way. ...and move the car back to its original position, facing the opposite direction.

Your Mission Write a function which will move a Car forward until it reaches a barrier... ...then the car is turned around... ...and returned to its original location, facing the opposite way. This is the end of the function’s work.

Your Mission void ricochet(Car& moving_car); Write a function which will move a Car forward until it reaches a barrier... ...then the car is turned around... ...and returned to its original location, facing the opposite way. The function, called ricochet, has the heading shown here. There is one parameter, called moving_car, which is the Car that the function manipulates. We will assume that the radio connection has already been made for this car, so all the function has to do is issue the necessary move and turn_around commands.

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. The first action the function takes is to check for a very simple case: the case where the car is already blocked. In this case, no movement is needed. All that the function needs to do is turn the car around, and leave it in the same place. NOTE: The lecturer can pretend to be the car, blocked at a wall, to demonstrate this simple case.

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: On the other hand, if the car is not blocked, then some movement is needed. The function begins the movement by moving the car forward just one foot. Notice that the move activation is not in a loop. We're just moving one foot, with the primary goal being to make a smaller version of the original problem. In fact, once the car has moved just a single foot forward, we do have a smaller version of the original problem... moving_car.move( ); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); This makes the problem a bit smaller. For example, if the car started 100 feet from the barrier... if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...as shown in this example. In this example, the car starts 100 feet from a barrier. moving_car.move( ); . . . 100 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); This makes the problem a bit smaller. For example, if the car started 100 feet from the barrier... then after activating move once, the distance is only 99 feet. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: After moving just one foot, the car is 99 feet from the barrier. moving_car.move( ); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); We now have a smaller version of the same problem that we started with. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: Since 99 feet is less than 100 feet, we have a smaller version of the original problem. moving_car.move( ); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); Make a recursive call to solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: Once a smaller problem has been created, we can make the key step of any recursive function: The ricochet function calls itself to solve the smaller problem! The act of a function calling itself is recursion, or in other words a recursive call. In order for recursion to succeed, the recursive call must be asked to solve a problem which is somehow smaller than the original problem. The precise meaning of "smaller" is given in Section 9.3, but for now you can use your intuition about what a "smaller" problem is. moving_car.move( ); ricochet(moving_car); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: The key idea to remember is this: When you make a recursive call to solve a smaller problem, the recursive call will successfully solve that smaller problem. In this case, that means that the recursive call will move the car 99 feet to the barrier... moving_car.move( ); ricochet(moving_car); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...as shown here and in the next few slides. moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: This is still work being done in the recursive call. moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: Still in that recursive call! moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: The work of the recursive call has taken the car to the barrier... moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...and turned the car around. moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: The recursive call is still working to solve the smaller problem... moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...eventually the recursive call will bring the car back... moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...to the position where the recursive call was made. moving_car.move( ); ricochet(moving_car); . . .

Pseudocode for ricochet void ricochet(Car& moving_car); The recursive call will solve the smaller problem. if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: At last! The recursive call has finished its work, solving the smaller problem. In the solution of the smaller problem, the recursive call moved the car forward to the barrier, turned the car around, and moved the car back to the starting position of the smaller problem, but facing the opposite direction Another key point: You don't need to know all the details of how that recursive call worked. Just have confidence that the recursive call will solve the smaller problem. You can safely have this confidence provided that: 1. When the problem gets small enough, there won't be more recursive calls, and 2. Each recursive call makes the problem "smaller". moving_car.move( ); ricochet(moving_car); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); What is the last step that's needed to return to our original location ? if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: After the recursive call solves the smaller problem, there is one more step that must be taken to solve the original problem. Question: What is that remaining step? moving_car.move( ); ricochet(moving_car); . . . 99 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); What is the last step that's needed to return to our original location ? if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: Answer: The car must be moved one more step to bring it back to its original position. moving_car.move( ); ricochet(moving_car); 100 ft.

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: This recursive function follows a common pattern that you should recognize. The pattern followed by this recursive function is a common one that you should be able to recognize and implement for similar problems. moving_car.move( ); ricochet(moving_car);

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: When the problem is simple, solve it with no recursive call. This is the base case or the stopping case. The start of the pattern is called the base case. This is the case where the problem is so simple that it can be solved with no recursion. Question: What do you suppose would happen if we forgot to include a base case? Answer: In theory, the recursion would never end. Each recursive call would make another recursive call which would make another recursive call, and so on forever. In practice, each recursive call uses some of the computer's memory, and eventually you will run out of memory. At that point, a run-time error occurs stating "Run-time stack overflow" or perhaps "Stack-Heap collision." Both messages mean that you have run out of memory to make function calls. moving_car.move( ); ricochet(moving_car);

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: When the problem is more complex, start by doing work to create a smaller version of the same problem... If the base case does not apply, then the algorithm will work by creating a smaller version of the original problem. moving_car.move( ); ricochet(moving_car);

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...use a recursive call to completely solve the smaller problem... The smaller problem is solved with a recursive call. moving_car.move( ); ricochet(moving_car);

Pseudocode for ricochet void ricochet(Car& moving_car); if moving_car.is_blocked( ), then the car is already at the barrier. In this case, just turn the car around. Otherwise, the car has not yet reached the barrier, so start with: ...and finally do any work that's needed to complete the solution of the original problem.. Generally a bit of extra work is done before the recursive call, in order to create the smaller problem. Work is often needed after the recursive call too, to finish solving the larger problem. Programmer's Hint: If you find that no work is needed after the recursive call, then you have a simple kind of recursion called "tail recursion". The word "tail" refers to the fact that the recursive call is the final thing the algorithm does. Tail recursion is nearly always a bad idea. The reason is that tail recursive algorithms can generally be written much simpler with a loop and no recursive call. moving_car.move( ); ricochet(moving_car);

Implementation of ricochet void ricochet(Car& moving_car) { if (moving_car.is_blocked( )) moving_car.turn_around( ); // Base case else { // Recursive pattern moving_car.move( ); ricochet(moving_car); } Look for this pattern in the other examples of Chapter 9. You'll find this same pattern in other problems of Chapter 9, such as the recursive functions to write the digits of a number vertically.

An Exercise Can you write ricochet as a new member function of the Car class, instead of a separate function? void Car::ricochet( ) { . . . Time for another quiz . . . Turn in in 5 minutes You have 2 minutes to write the implementation.

An Exercise One solution: void Car::ricochet( ) { if (is_blocked( )) turn_around( ); // Base case else { // Recursive pattern move( ); ricochet( ); } Two key points: 1. The recursive member function does not need a parameter, since it must be activated by a particular car. For example, if you have a car named racer, then you can activate racer's ricochet function with: racer.ricochet( ); 2. The recursive member function activates itself. Do you see where this happens?

Recursive Thinking: General Form Recursive Calls Suppose a problem has one or more cases in which some of the subtasks are simpler versions of the original problem. These subtasks can be solved by recursive calls Stopping Cases /Base Cases A function that makes recursive calls must have one or more cases in which the entire computation is fulfilled without recursion. These cases are called stopping cases or base cases

Tracing Recursive Calls: Ricochet Do it by hand if car is 4 feet away from the barrier void Car::ricochet( ) { if (is_blocked( )) A. turn_around( ); // Base case else { // Recursive pattern B. move( ); C. ricochet( ); D. move( ); E } } Two key points: (1) The recursive case and the stopping case (2) Activation record The return location only in this example – other information (the barrier) will be detected by the sensor on the car) (3) The running stack The collection of the activation records is stored in a stack data structure In the demo only the record of the recursive call is tracked

A Close Look at Ricochet Recursion The recursive case and the stopping case Activation record The return location only in this example – other information is kept in the object racer The running stack The collection of the activation records is stored in a stack data structure

Example 2: Write Number Vertically Task Write a non-negative integer to the screen with its decimal digits stacked vertically for example: Input 1234 Output: 1 2 3 4 Problem statement How can we write a program to do this? if 1234 is divided by 1000, then the quotient will be 1234/1000 = 1; if (1234-1*1000) = 234 is divided by 100, then the quotient will be 234/100 = 2; (234-2*100) = 34; 34/10 = 3; (34-3*10) = 4; How about 12345? It is much easier to do it in a reversed order n%10 ->the last digit n <- n/10; all the digit except the last

A possible function Write an integer number vertically void write_vertical (unsigned int number) // precondition: number >=0 // Postcondition: The digits of number have been written, stacked vertically. { assert(number>=0); do { cout << number % 10 << endl; // Write a digit number = number / 10; } while (number !=0); } First let’s use a simple while loop to try to solve this problem. We know how to get the last digit of a number by using the modulo function number%10 – this is the remainder upon dividing number by 10. Then we get the quotient by dividing the number by 10 - print the remainder until the number is zero. However the order of the digits is not want we desired – we want the number stacked in the reverse order – so the first approach is to use a stack to save the digits first, and then print the digits from the stack Input 1234 Output: 4 3 2 1

Approach 1: using a stack Write an integer number vertically void stack_write_vertical (unsigned int number) // Postcondition: The digits of number have been written, stacked vertically. { stack<int> s; do s.push(number % 10); // push a digit in the stack number = number / 10; } while (number !=0); while (!(s.empty())) cout << s.top()<< endl; //print a digit from the stack s.pop(); } Using a stack, we need at least two while loops – in the first while loop we push the digits in a stack; in the second one, we pop the digits from the stack after printing out the top. Can we accomplish our ask by a simpler coding – yes, using recursion

Approach 2: Using Recursion Write an integer number vertically void recursive_write_vertical(unsigned int number) // Postcondition: The digits of number have been written, stacked vertically. { if (number < 10) // stopping case cout << number << endl; // Write the one digit else // including recursive calls recursive_write_vertical(number/10); // Write all but the last digit cout << number % 10 << endl; // Write the last digit } Two cases: If the number only has one digit we simply print it out Otherwise we break the original task into two subtasks: First print all except the last digit, stacked vertically Then print the last digit The first subtask is a simpler instance of the same task of writing a number’s digits vertically. It’s simpler because number/10 has fewer digits This step can be implemented by making a recursive call of the original function

Tracing Recursive Calls Write an integer number vertically void recursive_write_vertical_2(unsigned int number) // Postcondition: The digits of number have been written, stacked vertically. { if (number < 10) // stopping case A cout << number << endl; // Write the one digit else // including recursive calls B recursive_write_vertical(number/10); // Write all but the last digit C cout << number % 10 << endl; // Write the last digit D } } Two key points: (1) The recursive case and the stopping case (2) Activation record The return location and one formal parameter of the calling function when a function is called – a recursive one or ordinary one (3) The running stack The collection of the activation records is stored in a stack data structure

A Closer Look at the Recursion Recursive Function Recursive calls Stopping (Base) cases Run-time Stack the collection of activation records is stored in the stack Activation Record - a special memory block including return location of a function call values of the formal parameters and local variables

Recursive Thinking: General Form Recursive Calls Suppose a problem has one or more cases in which some of the subtasks are simpler versions of the original problem. These subtasks can be solved by recursive calls Stopping Cases /Base Cases A function that makes recursive calls must have one or more cases in which the entire computation is fulfilled without recursion. These cases are called stopping cases or base cases

Self-Tests and More Complicated Examples An Extension of write_vertical (page 436) handles all integers including negative ones Hints: you can have more than one recursive calls or stopping cases in your recursive function Homework Reading: Section 9.1 Self-Test: Exercises 1-8 Advanced Reading: Section 9.2 Assignment 5 online

super_write_vertical Write any integer number vertically void super_write_vertical(int number) // Postcondition: The digits of the number have been written, stacked vertically. // If number is negative, then a negative sign appears on top. // Library facilities used: iostream.h, math.h { if (number < 0) cout << '-' << endl; // print a negative sign super_write_vertical(abs(number)); // abs computes absolute value // This is Spot #1 referred to in the text. } else if (number < 10) cout << number << endl; // Write the one digit else super_write_vertical(number/10); // Write all but the last digit // This is Spot #2 referred to in the text. cout << number % 10 << endl; // Write the last digit