A-level Computing 2009/AQA/Problem Solving, Programming, Operating Systems, Databases and Networking/Programming Concepts/Recursive Techniques





Recursion is a key area in computer science that relies on you being able to solve a problem by the cumulation of solving increasingly smaller instances of the same problem.



An example of recursion in a name is the GNU Operating System, you might well ask what GNU stands for:
 * GNU = GNU is Not Unix

Wait a minute, they have defined the name by restating the name!:
 * GNU
 * GNU is Not Unix
 * GNU is Not Unix is Not Unix
 * GNU is Not Unix is Not Unix is Not Unix
 * GNU is Not Unix is Not Unix is Not Unix is Not Unix
 * ad infinitum

Luckily for us, with computer code our recursion should tend towards an end as we are solving increasingly smaller instances of the same problem, we should be tending towards an end. With the GNU example the name always remains the same size, but with the following example there is an end:

A mother told a story of a bear to send her child to sleep
 * in which a bear told a story of a cat to send her cub to sleep
 * in which a cat told a story of a cow to send her kitten to sleep
 * in which the cow told a story of a bee to send her calf to sleep
 * in which the bee told a story of a pheasant to send her larva to sleep
 * the larva went to sleep
 * the calf went to sleep
 * the kitten went to sleep
 * the cub went to sleep

the child went to sleep

Let's take a look at some computer science examples

Factorial example
A classic computer example of a recursive procedure is the function used to calculate the factorial of a natural number:
 * $$n ! = n \times (n-1) \times (n-2) \times ... \times 1$$

For example:
 * $$3 ! = 3 \times  2  \times  1 = 6  \ $$
 * $$5 ! = 5 \times  4  \times  3  \times  2  \times  1 = 120  \ $$
 * $$10 ! = 10 \times  9  \times  8  \times  7  \times  6 \times 5 ! = 3628800  \ $$

Did you notice what I did with the final solution? Instead of writing 5 * 4 * 3 * 2 * 1, I used 5! which elicits the same result. Looking back our definition of why recursion is used, we seem to solve big problems by solving smaller instances of the same problem, so factorials are ripe for recursion: 10! = 10 * 9! 9! = 9 * 8! 8! = 8 * 7! 7! = 7 * 6! 6! = 6 * 5! 5! = 5 * 4! 4! = 4 * 3! 3! = 3 * 2! 2! = 2 * 1! 1! = 1 As we can see, each n! is the product of n * (n-1)!. In summary:
 * $$ \operatorname{fact}(n) =

\begin{cases} 1 & \mbox{if } n = 1 \\ n \cdot \operatorname{fact}(n-1) & \mbox{if } n > 1 \\ \end{cases} $$

Now let's have a look at how we would write code to solve this: It looks very simple and elegant. But how does it work?



Let's build a trace table and see what happens. This trace table will be different from the ones that you have built before as we are going to have to use a stack. If you haven't read up on stacks you must do so before continuing:

All is going well so far until we get to line 3. Now what do we do? We'll soon have two values of n, one for Function call 1 and one for Function call 2. Using the trace table as a stack (with the bottom of the stack at the top and the top of the stack at the bottom) we'll save all the data about the function call including its value of n and make note of what line we need to return to when we have finished with factorial(3).

We now have a similar situation to before, let's store the return address and go to factorial(2) We now have a similar situation to before, let's store the return address and go to factorial(1) Now we have another problem, we have found an end to the factorial(1). What line do we go to next? As we are treating our trace table as a stack we'll just pop the previous value off the top and look at the last function call we stored away, that is function call 3, factorial(2), and we even know what line to return to, line 3: We know that factorial(1) = 1 from the previous returned value. Therefore factorial(2) returns 2 * 1 = 2 Again we'll pop the last function call from the stack leaving us with function call 2, factorial(3) and line 3. We know that factorial(2) = 2 from the previous returned value. Therefore factorial(3) returns 3 * 2 = 6 Again we'll pop the last function call from the stack leaving us with function call 1, factorial(4) and line 3. We know that factorial(3) = 6 from the previous returned value. Therefore factorial(4) returns 4 * 6 = 24 We reach the end of function call 1. But where do we go now? There is nothing left on the stack and we have finished the code. Therefore the result is 24.

Fibonacci number example
Another good example is a method to calculate the Fibonacci numbers. By definition, the first two Fibonacci numbers are 0 and 1, and each subsequent number is the sum of the previous two.:
 * $$0,\;1,\;1,\;2,\;3,\;5,\;8,\;13,\;21,\;34,\;55,\;89,\;144,\; \ldots\;$$

For example, take the 6th number, 5. This is the sum of the 5th number, 3, and the 4th number, 2.

In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recursive statement
 * $$F_n = F_{n-1} + F_{n-2},\!\,$$

with the first two values being
 * $$F_0 = 0 \quad\text{and}\quad F_1 = 1.$$

Let's try and create a code version of this:

Recursion summary
Recursion does have some issues though, consider how much data we had to store on the stack for just 4 function calls. If we were to perform 1000, the memory used would be incredibly large.

Give the output of the following recursive function call recur(6):

6 5 4 3 2 1 0

Give the output of the following recursive function call recur(4):

1 2 3 4

Give the output of the following recursive function call recur(6):

11 10 9 8 7 6


 * Recursion can produce simpler, more natural solutions to a problem
 * Recursion takes up large amounts of computer resources storing return addresses and states