In Class: Week 11 Tuesday and Thursday:
Recursion
Create a week11 subdirectory in your
cs21/class directory by running update21:
$ update21
$ cd
$ cd cs21/class/week11
Topics
- Recursion
- Defining recursive functions
- Recursion on lists and strings
- Iteration vs Recursion
- Recursion using Graphics
- Dynamic programming
- Merge sort
In-class work
Recursion
- Open recursion.py. We are going to write some iterative and
recursive versions of the same function. Iterative versions use
loops, recursive versions do not use loops, and instead contain
calls to themselves but on a smaller problem.
The idea of recursive functions is based on
recursive definitions. For example, n! can be defined
as n(n-1)!.
- Lets try writing sum of ints together
- Next, try writing an iterative version (using a loop) of factorial
that takes a positive int value, n, and returns the product of the
first n integers.
- Next, try writing a recursive version of the factorial
function.
- For any recursive problem, think of three questions:
- What is the base case? That is, in what instances do I know what recursion to occur?
- What is the recursive call? Make one or calls in the function to itself.
It is very important to use different arguments in the recursive call otherwise
you obtain infinite recursion.
- Do all possible chains of recursion lead to a base case?
- Next, we will work on recursive algorithms for strings and lists. Open up
reverseWord.py and write a recursive function that returns the letters of a word in
reverse. For example, "hello should yield "olleh".
- Recursive functions can have more than one different recursive call
within the function. For example, let us work out how we can recursively
define binary search, which recursively calls binary search on one-half
of the problem. We will code our solution in recBinary.py
- Recursion plays in important role in mathematics and graphical
representations of seemingly complex objects. We will revisit our bulls eye
graphics example from early in the course to define a recursive solution
to the problem in recursiveCircle.py. A more advanced solution
can then be looked at in recursiveCircle2.py.
Dynamic Programming
- The Fibonacci sequence is a very popular recurrence relation from
mathematics. First, let us code up a Python implementation of a function
that can calculate the value of any position in the Fibonacci sequence
using a recursive function in fibonacci.py.
- Adding control flow statements, we see that the definition works on
small numbers, such as f(5). But when we try f(100), the program seems
to run forever. And looking at the flow, it seems to be repeating itself.
This is an example were the recursive definition contains overlapping
subproblems. A common solution to this is to use dynamic programming, where
we keep track of all previously solved Fibonacci values. Then, we create
an additional base case that checks to see if our list of solutions contains
the answer already. If it does, we return it, else with proceed with the
normal recurrence steps.
Merge Sort
- Last week, we looked at several sorting algorithms, all of which
had O(N^2) runtime. We will take a look at merge sort, a divide-and-conquer
algorithm with a similar pattern to binary search in that we divide our
problem in half successively into we reach small lists that are easy to sort.
- First, in partners, come up with an algorithm to combine two already
sorted lists into one. This is similar to the merge step in merge sort.
- Next, let's code up our solution for merge and our recursive
definition for merge sort in mergesort.py.
- When we analyze the run time of merge sort, we notice that on any
level of the recursion, the total amount of work being down by all of the
merges is O(N). That is, to combine two lists of size N/2, it takes O(N) time.
Similarly, combining two N/4 lists and combining another two N/4 lists
takes O(N) time in total. The next question is, how many levels
are there in merge sort? Since divide-and-conquer divides the problem
in half each time, we see that it takes O(lgN) recursions to reach
the base case, meaning that we do O(N) work a total of O(lg N) times resulting
in an O(N lg N) algorithm.
include("style/footer.php"); ?>