61A Lecture 20Friday, October 14Tree RecursionTree-shaped processes arise whenever executing the body of a function entails making more than one call to that function.2http://en.wikipedia.org/wiki/File:Fibonacci.jpg1, 2, 3, 4, 5, 6, 7, 8, 9,n:0, 1, 1, 2, 3, 5, 8, 13, 21,fib(n): ... , 5,702,887 ... , 35 def fib(n): if n == 1: return 0 if n == 2: return 1 return fib(n-2) + fib(n-1)A Tree-Recursive Process3fib(6)fib(5)fib(4)fib(2)1fib(3)fib(1) fib(2)0 1fib(3)fib(1) fib(2)0 1fib(4)fib(2)1fib(3)fib(1) fib(2)0 1The computational process of fib evolves into a tree structureDemoRepetition in Tree-Recursive Computation4fib(6)fib(4)fib(2)1fib(5)fib(3)fib(1) fib(2)0 1fib(3)fib(1) fib(2)0 1fib(4)fib(2)1fib(3)fib(1) fib(2)0 1This process is highly repetitive; fib is called on the same argument multiple timesMemoizationIdea: Remember the results that have been computed before5 def memo(f): cache = {} def memoized(n): if n not in cache: cache[n] = f(n) return cache[n] return memoizedDemoKeys are arguments that map to return valuesSame behavior as f, if f is a pure functionMemoized Tree Recursion6fib(6)fib(4)fib(2)1fib(5)fib(3)fib(1) fib(2)0 1fib(3)fib(1) fib(2)0 1fib(4)fib(2)1fib(3)fib(1) fib(2)0 1Call to fibFound in cacheCalls to fib without memoization:Calls to fib with memoization:fib(35)3518,454,929Iteration vs Memoized Tree RecursionIterative and memoized implementations are not the same.7 def fib_iter(n): prev, curr = 1, 0 for _ in range(n-1): prev, curr = curr, prev + curr return curr @memo def fib(n): if n == 1: return 0 if n == 2: return 1 return fib(n-2) + fib(n-1)n stepsn steps3 namesn entriesTime SpaceThe first Fibonacci numberScales with problem sizeIndependent of problem sizeCounting Change$1 = $0.50 + $0.25 + $0.10 + $0.10 + $0.05$1 = 1 half dollar, 1 quarter, 2 dimes, 1 nickel$1 = 2 quarters, 2 dimes, 30 pennies$1 = 100 pennies8How many ways are there to change a dollar?How many ways to change $0.11 with nickels & pennies?$0.11 can be changed with nickels & pennies byA. Not using any more nickels; $0.11 with just penniesB. Using at least one nickel; $0.06 with nickels & penniesCounting Change RecursivelyHow many ways are there to change a dollar?9 def count_change(a, kinds=(50, 25, 10, 5, 1)): <base cases> d = kinds[0] return count_change(a, kinds[1:]) + count_change(a-d, kinds)The number of ways to change an amount a using n kinds =•The number of ways to change a using all but the first kind+•The number of ways to change (a - d) using all n kinds, where d is the denomination of the first kind of coin.DemoSpace ConsumptionWhich environment frames do we need to keep during evaluation?Each step of evaluation has a set of active environments.Values and frames referenced by active environments are kept.Memory used for other values & frames can be reclaimed.10Active environments: •The environment for the current expression being evaluated•All environments for expressions that depend upon the value of the current expression•All environments associated with values referenced by active environmentsFibonacci Environment Diagram11fib(3)if n == 1: return 0if n == 2: return 1return fib(n-2) + fib(n-1)fib:fib(n):...n: 3fibfib(n-2)if n == 1: return 0if n == 2: return 1return fib(n-2) + fib(n-1)n: 1fib0Fibonacci Environment Diagram12fib(3)if n == 1: return 0if n == 2: return 1return fib(n-2) + fib(n-1)fib:fib(n):...n: 3fibfib(n-2)if n == 1: return 0if n == 2: return 1return fib(n-2) + fib(n-1)0n: 1fibfib(n-1)if n == 1: return 0if n == 2: return 1return fib(n-2) + fib(n-1)n: 2fibFibonacci Memory Consumption13fib(6)fib(5)fib(3)fib(2)1fib(4)fib(2)1fib(3)fib(1) fib(2)0 1fib(1)0fib(4)fib(2)1fib(3)fib(1) fib(2)0 1Assume we have reached this stepFibonacci Memory Consumption14fib(6)fib(5)fib(3)fib(2)1fib(4)fib(2)1fib(3)fib(1) fib(2)0 1fib(1)0fib(4)fib(2)1fib(3)fib(1) fib(2)0 1Assume we have reached this stepHas an active environmentCan be reclaimedHasn't yet been createdActive Environments for Returned Functions15make_adder:def make_adder(n): def adder(k): return k + n return adderadd1 = make_adder(1)make_adder(n):...make_adder(1)Associated with an environmentn: 1make_adderadder:adder(k):return k + n def adder(k): return k + n return adderTherefore, all frames in this environment must be kept
View Full Document