# How Slow is Recursive Fibonacci?

Examining the efficiency of a recursive method.

In lecture, we saw that the recursive solution to computing the Fibonacci numbers is **much** slower than the iterative version. How much slower? These were the results comparing the amount of time the two programs required for a few reasonably large values:

For example, computing `f(45)`

recursively required almost 3 1/2 seconds, while the iterative solution finished in less that 1 ms. So the recursive solution is (at least) 3,500 times slower than the iterative solution! But why?

## Recursive Calls

To understand why the recursive fibonacci method is so slow, it helps to understand how many “recursive calls” the method makes. That is, if we execute `fibonacci(n)`

, how many times does `fibonacci(<something>)`

actually get called? Here is the code for reference:

1
2
3
4
5

private static int fibonacci (int n) {
if (n <= 2) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}

For small values of `n`

, we can compute the number of recursive calls directly. For `n = 1`

and `n = 2`

, the function hits `return 1`

, without any recursive calls to `fibonacci(...)`

. Now `fibonacci(3)`

executes

1

return fibonacci(2) + fibonacci(1);

so there are 2 recursive calls made. What about `fibonacci(4)`

? In this case, we execute

1

return fibonacci(3) + fibonacci(2);

Thus there are 2 recursive calls again. But `fibonacci(3)`

itself makes 2 recursive calls (by the above), while `fibonacci(2)`

makes none. So the total number of calls to `fibonacci(<something>)`

by `fibonacci(4)`

is `2 + 2 + 0 = 4`

.

Note that we are already seeing some repeated work: `fibonacci(4)`

calls `fibonacci(3)`

and `fibonacci(2)`

, but `fibonacci(3)`

*also* calls `fibonacci(2)`

. So the code is computing the same thing twice, and having to waste time performing each repeated call!

The following figure shows the so-called **recursion tree** corresponding to an execution of `fibonacci(6)`

:

This tree illustrates which calls to `fibonacci`

(`fib`

in the image) make recursive calls. Note that `fib(4)`

gets called twice, `fib(3)`

three times, `fib(2)`

5 times, and `fib(1)`

3 times. That is a lot of wasted effort!

The diagram above is what computer scientists and mathematicians call a **tree.** The bottom-most nodes (labeled `fib(2)`

and `fib(1)`

) are the **leaves.** These correspond to the “base cases” in the recursion, as these cases do not make recursive calls to `fib`

. The **root** is the top-most node, labeled `fib(6)`

in our picture. Weirdly, mathematicians and computer scientists draw “trees” with “leaves” at the bottom and a “root” on top, which is the opposite of how an actual tree outside grows. Go figure.

##### Depth of recursion

The **depth** of a recursion tree is the is the length of the longest path from the root to any leaf. For example, in the image above, the longest path from the root (labeled `fib(6)`

) to any leaf is the path following the recursive calls `fib(5)`

, `fib(4)`

, `fib(3)`

, `fib(2)`

(or `fib(1)`

). This path has length 4 (there are 4 recursive calls along both the paths to `fib(2)`

and `fib(1)`

the path), so the **depth of recursion** for this computation of `fib(6)`

is 4.

## Computing the number of recursive calls

In general (for `n > 3`

), a call to `fibonacci(n)`

makes 2 recursive calls to `fibonacci(n-1)`

and `fibonacci(n-2)`

. These recursive calls in turn make more recursive calls. How many?

Well… we can compute it! We can write a method `numberOfCalls(int n)`

that counts the number of recursive calls `fibonacci(n)`

makes. Note that we should have

`numberOfCalls(1)`

returns 0`numberOfCalls(2)`

returns 0

On the other hand, for `n > 2`

, `fibonacci(n)`

makes recursive calls to `fibonacci(n-1)`

and `fibonacci(n-2)`

. So `numberOfCalls(n)`

should return `2 + \numberOfCalls(n-1) + \numberOfCalls(n-2)`

. So we are led to *another* recursive function definition:

1
2
3
4
5
6
7

private static int numberOfCalls (int n) {
if (n == 1 || n == 2) {
return 0;
}
return 2 + numberOfCalls(n - 1) + numberOfCalls(n - 2);
}

Here’s the the output for the first few values of `n`

:

Note the pattern: the number of recursive calls **almost doubles** each time `n`

increases by one. So computing `fibonacci(11)`

this way requires almost twice as much work as `fibonacci(10)`

, and so on. Obviously, this is wasteful!

A more efficient thing to do would be store each value of `fibonacci(n)`

when it is computed, say, in an array. Instead of re-computing each value from scratch, the program could then look up a value to see if it has been computed before. If so, it can simply fetch the stored value rather than making a new recursive call.

##### Question

How many recursive calls does `numberOfCalls(n)`

make?