15-112 Lecture 8 (July 12, 2012)

Recursion Practice

We spent a good chunk of today walking through simple recursion examples. These examples included the following:

Blobs, Solved

We talked a bunch about how to solve "Blobs" in Python. And, we wrote the recursive method on the board. But, we never put all of the pieces together, including reading in the map and also actually marking the 2D list. Please find the full implementation below, including a sample map of blobs, below.

Note the use of the "copy.deepcopy()" method to copy the grid to make the marking grid. This method makes a copy of the list, including the nested lists. A "shallow" copy() would copy the outer list and "point at" the inner lists. A simple assignment would "point at" the outer list.

Notice also that, since I put my functions in different files, I had to import them, using their file name as the module name. Subsequently, I had to prefix the imported methods with their module name, e.g. copyMap.copyMap(...)

It is probably also worth noting that I used a non-recursive "wrapper" function to hide some of the state that recursion needs from the user. This wrapper function calls the recursive function -- with the right initial state passed in.

Recursive Thinking, Without Recursion

It is important to realize that one can think and problem solve recursively -- even without the namesake recursive function calls. Recall that, recursion implements its magic by taking advantage of the fact that python automatically pushes a stack frame containing local variables and arguments onto the runtime stack as a function is called -- and pops them off upon its return. We can implement recursive thinking using loops by simulating recursion thorugh the use of our own stack. Specifically, we can use a list's append() and pop() methods to maintain the stack.

It is also worth noting that, if nothing happens after the recursive call, we are never taking advantage of the stack. This is a special case called tail recursion. Most of our simple examples were tail recrusive, e.g. pow2(). But, for example, the maze solver and the reverse method were not. Regardless, tail recursion can automatically be converted into iteration, and many languages, for efficiency, do exactly that.

We looked at a couple of examples in class, but I have not placed them here. It is a little beyond the scope of 15-112, because we only very rately need to emulate recursion in environments that support it -- but I thought you'd enjoy it.