The Recursion Pattern One way to do repetition – loops Another way – recursion – very powerful tool Recursion: when a method calls itself 1/more times Classic example--the factorial function: n! = 1· 2· 3· ··· · (n-1)· n Recursive definition: n * f (n 1) if n 2 f ( n) 1 else As a Python method (runs at O(n)): def fact(n): Fact (4) = 4*3*2*1 Fact(4) = 4 * ( 3 * ( 2 * 1) if n>=2: return n*fact(n-1) else return 1
Properties of a Recursive Method Recursive solutions have 3 rules / properties: Base case(s) – the terminating case – when to stop Values of the input variables for which we perform no recursive calls are called base cases (there should be at least one base case). Every possible chain of recursive calls must eventually
reach a base case.
Recursive calls Calls to the current method.
Each recursive call should be defined so that it makes
Recursion Goldwasser 5 How does recursion work? When a function is called the flow of execution from where the call is made is interrupted and execution jumps to the function. When the function ends, execution returns to where it was interrupted – in the calling program How does the compiler know where to return? When a function is called, an activation record is created with function info One piece of info is the return address – location of next instruction to be executed when the function terminates A separate activation record is created for EACH function call – even to the same function
Visualizing Binary Search We consider three cases: If the target equals data[mid], then we have found the target. If target < data[mid], then we recur on the first half of the sequence. If target > data[mid], then we recur on the second half of the sequence.
Types of Recursion Linear Recursion The body of the function makes at most ONE new call to the recursive function (binary search & factorial) Binary search runs at O(logn) time constraint Other linear recursion runs at O(n) time – e.g. factorial Binary Recursion The body of the function makes TWO recursive calls to the recursive function (Fibonacci) Often runs at O(n2) Multiple Recursion The body of the function makes more than TWO calls to the recursive function Often runs at O(nk), where k is the number of recursive calls in the function
Computing Powers The power function, p(x,n)=xn, can be defined recursively: ì 1 if n = 0 p ( x , n) = í î x × p( x, n - 1) else This leads to an power function that runs in O(n) time (for we make n recursive calls). Power(2,5) =return 2* power(2,4) def power(x,n): return 2* 2* power(2,3) if n == 0: return 2*2*2*power(2,2) return 1 return 2*2*2*2*power(2,1) else: return 2*2*2*2*2*power(2,0 return x* power(x, n-1) return 2*2*2*2*2*1 32
Tail Recursion Tail recursion occurs when a linearly recursive method makes its recursive call as its last step. The binary_search method is an example. Such methods can easily be converted to non- recursive methods (which saves on some resources). def binarySearch(arr, low, high, target): if low<=high: mid = (high + low) // 2 if arr[mid] == target: return mid elif arr[mid] > target: return binarySearch(arr, low, mid - 1, target) else: return binarySearch(arr, mid + 1, high, target) else: return -1
Binary Recursion- Fibonacci Numbers Fibonacci numbers are defined recursively: F0 = 0 F1 = 1 Fi = Fi-1 + Fi-2 for i > 1. Recursive algorithm (first attempt): A call to the function fib(n) – has the recursive call return fib(n-1) + fib(n-2) So for each n, fib is called twice Therefore the time complexity is O(n2)