Recursion


For this assignment you will need the following file: recursion.cpp

What is recursion?

A recursive algorithm for solving a problem is an algorithm that works by dividing the problem into several problems of a smaller size and by applying the same algorithm to at least one of the smaller problems. Applying the same algorithm to a subproblem of a problem is called a recursive step. Size of a problem may mean different things for different problems, for instance the number of elements to sort for a sorting problem, or the number whose factorial we need to compute for a problem of computing a factorial.

All recursive algorithms are based on the idea that if we keep dividing a problem into problems of a smaller size, then eventually we'll get to a problem (or problems) which is so small that the solution for it is trivial. Such small problem is called a base case. There may be recursive algorithms with one or several base cases.

In programming, a recursive algorithm is usually implemented by a recursive function, i.e. a function that makes a call to itself. A recursive function must have a base case (or base cases), otherwise it will be looping forever. However, even having a base case does not guarantee that recursion always stops: one has to check that the function reaches a base case for all arguments.

How to solve a problem recursively.

  1. Think of a way of breaking the problem into smaller problems. Now assume that all or some of these problems are already solved. Can you construct the solution of the whole problem from solution(s) of the smaller problem(s)? If yes, then this is a potential recursive solution.
  2. Take the potential recursive solution and check that the size of the problem gets smaller with every iteration. For this you need to figure out what is the size of the problem that you are solving.
  3. Figure out what are the base cases. Check that the algorithm reaches a base case for any input.
  4. Write down your algorithm on paper and test it for several cases.
  5. Write the implementation of your algorithm in C++ or other programming language, test it on several inputs to make sure that it works in all cases. Choose inputs that are different from one another (for instance, use both odd and even numbers, small and large numbers, etc.)

A simple example: computing a power of a number.

Problem: given an integer base b and an integer positive exponent e, compute b**e(b raised to the power e).
  1. We notice that if we already know the value of b**(e-1) (b raised to the power e - 1), then we can get the value of b**e by multiplying b**(e-1) by b.
  2. If we take e to be the size of the problem, then the size of the problem reduces by 1 on every iteration.
  3. Base case: if e equals 1, then b**e is just b. Since e reduces by 1 on every step, then eventually it will reach 1, no matter what the initial value was.
  4. The algorithm will look something like this:
        To compute b raised to the power e:
        Base case: if e is 1, return b.
        Recursive step: if e > 1, multiply b by b raised to the power e-1. 
    
    Test algorithm for b = 2 and e = 3:
        (2 raised to the power 3) = (2 multiplied by (2 raised to the power 2))
        = (2 multiplied by (2 multiplied by (2 raised to the power 1))) =
        = (2 multiplied by (2 multiplied by 2)) = 2 * 2 * 2 = 8. 
    
  5. The C++ function implementing the algorithm is:
    int power (int base, int exponent)
    {
      if (exponent == 1)
        return base;
      else 
        return base * power(base, exponent - 1);
    }
    
    The function can be easily tested using he program test.cpp.

Assignment for this lab.

If you have not done so already, please download the file recursion.cpp. In the end of the lab, please submit handwritten answers to the questions below.

Palindrome problem.

A palindromes is a word that reads the same way forward and backward, for example "radar" or "noon". We want to determine if a given word is a palindrome.

Ideas for the algorithm.

To construct a recursive algorithm, think of the following: suppose I know that a part of a word is a palindrome. Is there a way to say that the whole word is a palindrome? Which part of the word do you need to know to be a palindrome?

Is the part of the word that you need to know shorter than the whole word? By how many letters?

What would you suggest for base case(s)?

In which case can you easily tell that a word is not a palindrome?

Let us try to write down the algorithm (not C++ code yet) and test it on words "noon", "common", "eve", "rear". Can you think of other good test examples?

Writing code for IsPalindrome(char str[], int length)

Exercise 1 Fill in the missing code for the function IsPalindrome based on your algorithm. Do not change the code already given.

Important: the function IsPalindrome takes two arguments: a string (i.e. an array of characters without the string termination constant \0) and the length of the string. The reason why we need to pass the length of the string as an argument is that the string passed to a function is only part of a word, i.e. it does not end with the string termination character, and so we can not use the function strlen inside IsPalindrome to determine the length of the string (strlen works only for strings that end with \0). Make sure that you pass the correct value as the length of the string.

When you have written the code, compile it with the command

g++ -Wall -o recursion recursion.cpp
(so that the name of the executable is recursion)

Testing the program

Read code for main carefully. Notice that the program reads words in a loop and prints back only those that are palindromes, ignoring the rest of the words. To stop the program, type Ctrl-D on a new line.

Question 1. Show (on paper) how the program works on words "radar" and "river". How many function calls are made for each of these words?

Question 2. What are base cases of the function? Why are these cases sufficient?

Running the program on the dictionary file: fun part of the lab :-)

Programs that read data until the end of input, such as this one, may be given a file as an input. This is done via redirection. For instance, we can run this program on the standard dictionary file used for spell-checking. This file contains all English words that the spell-checker considers correct. By running the program on this file we can print out all English palindromes. To do this, type:
    recursion < /usr/share/lib/dict/words
(recursion is the name of the executable). You can use any file as an input for this program by typing
    recursion < file name
Note that reading until the end of input (i.e. until the end of the data file) is done by the loop
    while (cin >> word) { ... }
Question 3. What are all palindromes in the dictionary file that start with letter r?


BU CAS CS - Recursion.
This page created by Elena Machkasova <elenam@cs.bu.edu>, modified by Jing Zhong<jingzh@bu.edu>