Data Structures and Algorithms with Object-Oriented Design Patterns in Python
next up previous index

Example-Fibonacci Numbers

 

In this section we will compare the asymptotic running times of two different programs that both compute Fibonacci numbers.gif The Fibonacci numbers  are the series of numbers tex2html_wrap_inline59867, tex2html_wrap_inline59869, ..., given by

  equation2048

Fibonacci numbers are interesting because they seem to crop up in the most unexpected situations. However, in this section, we are merely concerned with writing an algorithm to compute tex2html_wrap_inline59871 given n.

Fibonacci numbers are easy enough to compute. Consider the sequence of Fibonacci numbers

displaymath59861

The next number in the sequence is computed simply by adding together the last two numbers--in this case it is 55=21+34. Program gif is a direct implementation of this idea. The running time of this algorithm is clearly O(n) as shown by the analysis in Table gif.

   program2057
Program: Non-recursive program to compute Fibonacci numbers.

 

 

statement time
2 O(1)
3 O(1)
4 O(1)
5 tex2html_wrap_inline59885
6 tex2html_wrap_inline59887
7 tex2html_wrap_inline59887
8 tex2html_wrap_inline59887
9 tex2html_wrap_inline59887
10 O(1)
TOTAL O(n)
Table: Computing the running time of Program gif.

Recall that the Fibonacci numbers are defined recursively: tex2html_wrap_inline59899. However, the algorithm used in Program gif is non-recursive --it is iterative . What happens if instead of using the iterative algorithm, we use the definition of Fibonacci numbers to implement directly a recursive algorithm ? Such an algorithm is given in Program gif and its running time is summarized in Table gif.

   program2087
Program: Recursive program to compute Fibonacci numbers.

 

 

time

statement

n<2 tex2html_wrap_inline59903
2 O(1) O(1)
3 O(1) --
5 -- T(n-1)+T(n-2)+O(1)
TOTAL O(1) T(n-1)+T(n-2)+O(1)
Table: Computing the running time of Program gif.

From Table gif we find that the running time of the recursive Fibonacci algorithm is given by the recurrence

displaymath59862

But how do you solve a recurrence containing big oh expressions?

It turns out that there is a simple trick we can use to solve a recurrence containing big oh expressions as long as we are only interested in an asymptotic bound on the result. Simply drop the tex2html_wrap_inline57621s from the recurrence, solve the recurrence, and put the tex2html_wrap_inline57621 back! In this case, we need to solve the recurrence

displaymath59863

In the previous chapter, we used successfully repeated substitution to solve recurrences. However, in the previous chapter, all of the recurrences only had one instance of tex2html_wrap_inline57757 on the right-hand-side--in this case there are two. As a result, repeated substitution won't work.

There is something interesting about this recurrence: It looks very much like the definition of the Fibonacci numbers. In fact, we can show by induction on n that tex2html_wrap_inline59925 for all tex2html_wrap_inline58503.

extbfProof (By induction).

Base Case There are two base cases:

eqnarray2116

Inductive Hypothesis Suppose that tex2html_wrap_inline59925 for tex2html_wrap_inline59931 for some tex2html_wrap_inline59027. Then

eqnarray2121

Hence, by induction on k, tex2html_wrap_inline59925 for all tex2html_wrap_inline58503.

So, we can now say with certainty that the running time of the recursive Fibonacci algorithm, Program gif, is tex2html_wrap_inline59941. But is this good or bad? The following theorem shows us how bad this really is!

Theorem (Fibonacci numbers)     The Fibonacci numbers are given by the closed form expression

  equation2135

where tex2html_wrap_inline59943 and tex2html_wrap_inline59945.

extbfProof (By induction).

Base Case There are two base cases:

eqnarray2147

Inductive Hypothesis Suppose that Equation gif holds for tex2html_wrap_inline59931 for some tex2html_wrap_inline59027. First, we make the following observation:

eqnarray2161

Similarly,

eqnarray2165

Now, we can show the main result:

eqnarray2171

Hence, by induction, Equation gif correctly gives tex2html_wrap_inline59871 for all tex2html_wrap_inline58503.

Theorem gif gives us that tex2html_wrap_inline59955 where tex2html_wrap_inline59943 and tex2html_wrap_inline59945. Consider tex2html_wrap_inline59961. A couple of seconds with a calculator should suffice to convince you that tex2html_wrap_inline59963. Consequently, as n gets large, tex2html_wrap_inline59967 is vanishingly small. Therefore, tex2html_wrap_inline59969. In asymptotic terms, we write tex2html_wrap_inline59971. Now, since tex2html_wrap_inline59973, we can write that tex2html_wrap_inline59975.

Returning to Program gif, recall that we have already shown that its running time is tex2html_wrap_inline59941. And since tex2html_wrap_inline59975, we can write that tex2html_wrap_inline59981. That is, the running time of the recursive Fibonacci program grows exponentially with increasing n. And that is really bad in comparison with the linear running time of Program gif!

Figure gif shows the actual running times of both the non-recursive and recursive algorithms for computing Fibonacci numbers.gif Because the largest Python plain integer is 2147483647, it is only possible to compute Fibonacci numbers up to tex2html_wrap_inline59985 before the Python virtual machine starts computing with long integers (at which point our model of computation no longer applies).

The graph shows that up to about n=30, the running times of the two algorithms are comparable. However, as n increases past 30, the exponential growth rate of Program gif is clearly evident. In fact, the actual time taken by Program gif to compute tex2html_wrap_inline59991 was in excess of SOMETHING!

   figure2223
Figure: Actual running times of Programs gif and gif.


next up previous index

Bruno Copyright © 2003, 2004 by Bruno R. Preiss, P.Eng. All rights reserved.