Dynamic programming

One more recursive example

Last time we saw this tree method:

def to_list_at(self, node):
    if not node:
        return []
    return self.to_list_at(node.left) + [node.data] + self.to_list_at(node.right)

def to_list(self):
    return self.to_list_at(self.root)

Let’s walk through its execution on a small tree:

name value
s loc 1
location data
loc 1 BST { root -> loc 2 }
loc 2 BSTNode { data -> 10, parent -> None, left -> loc 3, right -> loc 4 }
loc 3 BSTNode { data -> 7, parent -> loc 3, left -> None, right -> None }
loc 4 BSTNode { data -> 20, parent -> loc 3, left -> None, right -> None }

See the lecture capture for details.

Where we’ve been and where we’re going

On the first day of class, I talked about the two big themes of the course: algorithms and software engineering. I’d like to revisit those themes in the context of what we’ve learned so far.

Algorithms Software engineering
while loops  
sorting  
  objects
  encapsulation
  polymorphism
  inheritance
trees trees
linked lists linked lists
iteration vs. recursion  

At the end of the week, we’re going to transition to a new programming language, Scala. Before we get there, we’re going to discuss one more algorithmic technique, called dynamic programming.

Recursion revisited

The Fibonacci sequence is defined by the following function:

Fib(0) = 1
Fib(1) = 1
Fib(n) = Fib(n - 1) + Fib(n - 2) [when n > 1]

How would we implement the fibonacci sequence in Python? The natural way might be to write something like this:

def fib(n):
    if n == 0:
        return 1
    if n == 1:
        return 1
    return fib(n - 1) + fib(n - 2)

We can step through the computation of fib(4) (which will only require the program dictionary, not memory). See lecture capture for details.

This solution works, but we might be able to come up with something more efficient. In computing fib(4), how many times is fib(2) called? It’s called twice: once in computing fib(4) and once when computing fib(3). How can we do better?

def fib(n):
    fibs = [0, 1]
    i = 2
    while i <= n:
        fibs.append(fibs[i - 1] + fibs[i - 2])
    return fibs[n]

This solution uses dynamic programming, which we’ll talk more about next class.