CSE 428: Lecture 7


The power of recursion

We illustrate the power of recursion with two examples. In both cases, the recursive solution is easy and compact, while an iterative solution would be rather complicated.

Example 1: Permutations of an array

The permutations of a set S are defined recursively as
Perm(S) = { ax | a is in S and x is in Perm(S\{a}) }
For instance, is S is the set {a,b,c}, then Perm(S) contains the following 6 sequences:
abc , acb , bac , bca , cab , cba

Assuming that the elements of S are stored in an array A with n+1 elements (whose positions range from 0 to n), we can write a recursive procedure printing all the permutations in the follwing way:

   procedure perm(i:integer);
      var j:integer;
      begin
      if i=n then print_array
             else for j:=i to n do
                      begin
                      swap(A[i],A[j]);
                      perm(i+1);
                      swap(A[i],A[j])
                      end
      end;
The procedure should be called with the command
   perm(0);

Example 2: Exit from a maze

We want to write a program that checks whether it is possible to exit from a given maze, starting from a certain position. The maze can be represented as a bidimentional array of characters. For instance we can represent by ' ' (blank) a position where we can walk, and by '*' a position where we cannot walk (a brick, or wall). The following is an example of a maze. 'x' represents the starting position.
   **** ****
   ***  *  *
   *** ** **
   *    x **
   *********

In this maze it is possible to reach the exit. Note that a maze might contain a loop, like for instance in the following case:

   *********
   ***    **
   *** ** **
     *  x **
   *********
We want of course to avoid looping forever; we want the program to be able to detect that a certain position has been already visited and avoid passing through it again. Note that, in this second example, it is not possible to reach the exit. In this case, the program should terminate with failure.

The following Pascal-like program is a possible solution. The type "position" represents a position in the array, i.e. a pair [i,j] (i is the index of row, ranging from 0 to m, and j is the index of column, ranging from 0 to n). We use the boolean var parameter "found" to indicate whether we have found the exit or not. The names of auxiliary procedures and functions should be self-explicatory.

   procedure search_exit(p:position; var found:boolean);
      begin
      if on_the_wall(p)
         then found := false
         else if on_the_border(p) 
                 then found := true
                 else begin
                      put_a_brick(p);
                      search_exit(north(p),found);
                      if not found
                         then begin
                              search_exit(east(p),found);
                              if not found
                                 then begin
                                      search_exit(south(p),found);
                                      if not found
                                         then search_exit(west(p),found)
                                      end
                              end
                      end
       end
The following is the C version of the same procedure:
   void search_exit(int i, int j, int *found){
        if (A[i][j] == '*') 
             *found = 0;
        else if (i==0 || i==m || j==0 || j==n) 
             *found = 1;
        else {
             A[i][j] = '*';
             search_exit(i-1,j,found);
             if (! *found){ 
                search_exit(i,j+1,found);
                if (! *found){ 
                   search_exit(i+1,j,found);
                   if (! *found)
                      search_exit(i,j-1,found);
                }
             }
        }
   }