Introduction to Computing Science and Programming I Recursion Introduction to Computing Science and Programming I
Recursion Remember that the factorial function, x!, is defined as x * (x-1) * (x-2)…*2*1 Here’s a solution to this using a for loop def factorial(x): ans = 1 for i in range(x): ans = ans * (i+1) return ans
Recursion There’s another way you can define the factorial function x! = x * (x-1)! = x * (x-1) * (x-2)! = x * (x-1) * (x-2) *… * 1 * 0! 0! = 1 by definition In this way the function can be defined in terms of itself. In code you can call a function from within itself, this is recursion.
Recursion Recursion takes place when a function calls itself. The basic goal is to find a simpler version of the same function. Another factorial function definition def factorial(x): if (x==0): return 1 else: return x * factorial(x-1)
Recursion What happens when we call factorial(3) factorial(3) makes a call to factorial(2) factorial(2) makes a call to factorial(1) factorial(1) calls factorial(0) factorial(0) returns 1 factorial(1) completes and returns 1 Now factorial(2) can complete and returns 2 And factorial(3) can complete and returns 6
Recursion The factorial function illustrates the two parts the every recursive function needs to have. 1. The recursion def factorial(x): if (x==0): return 1 else: return x * factorial(x-1) The recursion is where the function calls itself where it needs the answer to a simpler (smaller) version of the problem. factorial(x) needs the answer to factorial(x-1) to complete
Recursion 1. The base case def factorial(x): if (x==0): return 1 else: return x * factorial(x-1) The base case gives a point where the problem doesn’t need to be broken down into a smaller version. What would happen without a base case?
Recursion How to set up a recursive function. Find a simpler subproblem This is the recursion. Each recursive call should bring the problem closer to the base case. Find a base case that doesn’t require a recursive call. Make sure you don’t make a recursive call before you check the base case. def factorial(x): ans = x * factorial(x-1) if x==0: ans = 1 return ans
Recursion Recursion can be used to reverse the order of items in a list. The subproblem isn’t as obvious as it was with the factorial example. If you reverse the tail of a list (all but the first element) and then append the head (first element) you’ve reversed the list. [1, 2, 3, 4] ---> [4, 3, 2, 1] [2, 3, 4] ---> [4, 3, 2]
Recursion So we have our recursion. We’ll repeatedly call reverse for the tail of the list. At what point do we reach a base case? A list that is empty or has one element is the reverse of itself, so this would be a good spot to end the recursion.
Recursion Reverse List function def reverseList(x): if len(x) <= 1: return x ans = reverseList(x[1:]) ans = ans.append(x[0]) return ans
Recursion Triangle of numbers We want to print a triangle of numbers with a given number of rows. if rows = 5 1 12 123 1234 12345
Recursion If we want to print a triangle with 5 rows, we first need to print out the first four rows. This will be our recursive case. Once we get down to printing out a single row we don’t need to recurse any more so this will be our base case.
Recursion def numTriangle(rows): if rows == 0: return else: line = “” for i in range(rows): line = line + str(i+1) print line
Recursion Remember that the sorting algorithms we looked at had running time n2 while the best algorithms have running time n log n One of these n log n algorithms is merge sort. Merge sort uses the idea of splitting the problem into smaller pieces and recursion to get this advantage.
Recursion The basic idea behind merge sort [3, 6, 9, 4, 1, 7, 2, 8] Split the list into two halves Recursively sort each half Merge th two sorted halves [3, 6, 9, 4, 1, 7, 2, 8] [3, 6, 9, 4] [1, 7, 2, 8] [3, 6] [9, 4] [1, 7] [2, 8] [3] [6] [9] [4] [1] [7] [2] [8] We reached the base case, so now start merging. [3, 6] [4, 9] [1, 7] [2, 8] [3, 4, 6, 9] [1, 2, 7, 8] [1, 2, 3, 4, 6, 7, 8, 9]