EECS 110 Lec 4 Functions and Recursion Aleksandar

  • Slides: 74
Download presentation
EECS 110: Lec 4: Functions and Recursion Aleksandar Kuzmanovic Northwestern University http: //cs. northwestern.

EECS 110: Lec 4: Functions and Recursion Aleksandar Kuzmanovic Northwestern University http: //cs. northwestern. edu/~akuzma/classes/EECS 110 -s 09/

Functioning in Python # my own function! def dbl( x ): """ returns double

Functioning in Python # my own function! def dbl( x ): """ returns double its input, x """ return 2*x

Functioning in Python # my own function! def dbl( x ): """ returns double

Functioning in Python # my own function! def dbl( x ): """ returns double its input, x """ return 2*x keywords Some of Python's baggage… def starts the function return stops it immediately and sends back the return value Comments They begin with # Docstrings They become part of python's built-in help system! With each function be sure to include one that (1) describes overall what the function does, and (2) explains what the inputs mean/are

Functioning in Python def undo(s): """ this "undoes" its string input, s """ return

Functioning in Python def undo(s): """ this "undoes" its string input, s """ return 'de' + s >>> undo('caf'))

Conditional Statements ax**2 + bx + c = 0 If b**2 – 4*a*c is

Conditional Statements ax**2 + bx + c = 0 If b**2 – 4*a*c is less than 0, then the equation has no solution If b**2 – 4*a*c is equal to 0, then the equation has 1 solution If b**2 – 4*a*c is greater than 0, then the equation has 2 solutions

Striving for simplicity… def qroots(a, b, c): """ qroots(a, b, c) returns a list

Striving for simplicity… def qroots(a, b, c): """ qroots(a, b, c) returns a list of the real-number solutions to the quadratic equation ax**2 + bx + c = 0 input a: a number (int or float) input b: a number (int or float) input c: a number (int or float) """ if b**2 - 4*a*c < 0: # If b**2 – 4*a*c is less than 0 # then the equation has no solution return [ ] if b**2 - 4*a*c == 0: return [-b/(2*a)] # If b**2 – 4*a*c is equal to 0 # then the equation has one solution else: # Otherwise, the equation has 2 solutions return [(-b-(b**2 - 4*a*c)**0. 5)/(2*a), (-b+(b**2 4*a*c)**0. 5)/(2*a)]

Naming data == Saving time def qroots(a, b, c): """ qroots(a, b, c) returns

Naming data == Saving time def qroots(a, b, c): """ qroots(a, b, c) returns a lost of the real-number solutions to the quadratic equation ax**2 + bx + c = 0 input a: a number (int or float) input b: a number (int or float) input c: a number (int or float) """ d = b**2 - 4*a*c if d < 0: return [ ] if d == 0: return [ -b/(2*a) ] r 1 = (-b + d**0. 5)/(2*a) r 2 = (-b - d**0. 5)/(2*a) if r 1 > r 2: return [ r 2, r 1 ] else: return [ r 1, r 2 ] Simpler to fix, if needed! Faster to run, as well…

Naming data == Saving time def qroots(a, b, c): """ qroots(a, b, c) returns

Naming data == Saving time def qroots(a, b, c): """ qroots(a, b, c) returns a lost of the real-number solutions to the quadratic equation ax**2 + bx + c = 0 input a: a number (int or float) input b: a number (int or float) input c: a number (int or float) """ d = b**2 - 4*a*c Name once - use often! if d < 0: return [ ] if d == 0: return [ -b/(2*a) ] r 1 = (-b + d**0. 5)/(2*a) r 2 = (-b - d**0. 5)/(2*a) if r 1 > r 2: return [ r 2, r 1 ] else: return [ r 1, r 2 ] Simpler to fix, if needed! Faster to run, as well…

Functioning Python… # data gets named on the way IN to a function defs

Functioning Python… # data gets named on the way IN to a function defs must be at the very left def qroots(a, b, c): """ qroots(a, b, c) returns a lost of roots to the quadratic equation ax**2 + bx + c = 0 input a: a number (int or float) Docstrings input b: a number (int or float) become part of input c: a number (int or float) """ python's help Indenting d = b**2 - 4*a*c system if d < 0: indicates return [ ] code "blocks" qroots "block" is 11 lines if d == 0: return [ -b/(2*a) ] r 1 = (-b + d**0. 5)/(2*a) r 2 = (-b - d**0. 5)/(2*a) if r 1 > r 2: return [ r 2, r 1 ] else: return [ r 1, r 2 ] # notice that we don't get to name data on the way out…

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) def g(x): return -1 * x What is demo(-4) ?

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) def g(x): return -1 * x What is demo(-4) ? demo x = -4 return -4 + f(-4)

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f def g(x): return -1 * x What is demo(-4) ? x = -4 return 11*g(x) + g(x/2)

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f def g(x): return -1 * x x = -4 return 11*g(x) + g(x/2) These are different x's ! What is demo(-4) ?

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f x = -4 return 11*g(-4) + g(-4/2) def g(x): return -1 * x g What is demo(-4) ? x = -4 return -1. 0 * x

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f x = -4 return 11* 4 def g(x): return -1 * x g What is demo(-4) ? x = -4 return -1 * -4 + g(-4/2) 4

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f def g(x): return -1. 0 * x What is demo(-4) ? x = -4 return 11* 4 + g(-4/2)

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f x = -4 return 11* 4 def g(x): return -1 * x g What is demo(-4) ? x = -2 return -1 * -2 + g(-4/2) 2

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f def g(x): return -1. 0 * x What is demo(-4) ? x = -4 return 11* 4 + 2

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + f(-4) f def g(x): return -1. 0 * x What is demo(-4) ? x = -4 return 11* 4 + 2 46

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) +

How functions work… def demo(x): return x + f(x) def f(x): return 11*g(x) + g(x/2) demo x = -4 return -4 + def g(x): return -1. 0 * x What is demo(-4) ? 42 46

Thinking sequentially factorial 5! = 120 5! N! = = 5 * 4 *

Thinking sequentially factorial 5! = 120 5! N! = = 5 * 4 * 3 * 2 * 1 N * (N-1) * (N-2) * … * 3 * 2 * 1

Thinking recursively factorial 5! = 120 Recursion == selfreference! 5! = 5 * 4

Thinking recursively factorial 5! = 120 Recursion == selfreference! 5! = 5 * 4 * 3 * 2 * 1 N! = N * (N-1) * (N-2) * … * 3 * 2 * 1 N! = N * (N-1)!

Warning This is legal code! def fac(N): return N * fac(N-1)

Warning This is legal code! def fac(N): return N * fac(N-1)

Warning def fac(N): return N * fac(N-1) No base case -- the calls to

Warning def fac(N): return N * fac(N-1) No base case -- the calls to factorial will never stop! Make sure you have a base case, then worry about the recursive step. . .

Thinking recursively ! def fac(N): if N <= 1: return 1 Base Case

Thinking recursively ! def fac(N): if N <= 1: return 1 Base Case

Thinking recursively ! def fac(N): if N <= 1: return 1 Base Case else:

Thinking recursively ! def fac(N): if N <= 1: return 1 Base Case else: return N * fac(N-1) Human: Base case and 1 step Recursive Step Computer: Everything else

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(1) Result: 1 The base case is No Problem!

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5)

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4)

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * fac(3)

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * fac(3) 3 * fac(2)

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * fac(3) 3 * fac(2) 2 * fac(1)

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) "The Stack" 5 * fac(4) 4 * fac(3) Remembers all of the individual calls to fac 3 * fac(2) 2 * fac(1) 1

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * fac(3) 3 * fac(2) 2 * 1

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * fac(3) 3 * 2

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * fac(4) 4 * 6

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N

def fac(N): if N <= 1: return 1 Behind the curtain… else: return N * fac(N-1) fac(5) 5 * 24

Recursion Mantra Let recursion do the work for you.

Recursion Mantra Let recursion do the work for you.

Recursion Mantra Let recursion do the work for you. Exploit self-similarity Produce short, elegant

Recursion Mantra Let recursion do the work for you. Exploit self-similarity Produce short, elegant code Less work !

Recursion Mantra Let recursion do the work for you. Exploit self-similarity Produce short, elegant

Recursion Mantra Let recursion do the work for you. Exploit self-similarity Produce short, elegant code Less work ! def fac(N): You handle the base case – the easiest possible case to think of! if N <= 1: return 1 Recursion does almost all of the rest of the problem! else: return N * fac(N-1)

One Step But you do need to do one small step… def fac(N): if

One Step But you do need to do one small step… def fac(N): if N <= 1: return 1 else: return fac(N) You handle the base case – the easiest possible case to think of! This will not work

Breaking Up… is easy to do with Python. s = "this has 2 t's"

Breaking Up… is easy to do with Python. s = "this has 2 t's" How do we get at the initial character of s? How do we get at ALL THE REST of s? L = [ 21, 5, 16, 7 ] How do we get at the initial element of L? How do we get at ALL the REST of L?

Breaking Up… is easy to do with Python. s = "this has 2 t's"

Breaking Up… is easy to do with Python. s = "this has 2 t's" How do we get at the initial character of s? How do we get at ALL THE REST of s? L = [ 21, 5, 16, 7 ] How do we get at the initial element of L? How do we get at ALL the REST of L? s[0]

Breaking Up… is easy to do with Python. s = "this has 2 t's"

Breaking Up… is easy to do with Python. s = "this has 2 t's" s[0] s[1: ] How do we get at the initial character of s? How do we get at ALL THE REST of s? L = [ 21, 5, 16, 7 ] How do we get at the initial element of L? How do we get at ALL the REST of L?

Breaking Up… is easy to do with Python. s = "this has 2 t's"

Breaking Up… is easy to do with Python. s = "this has 2 t's" s[0] s[1: ] How do we get at the initial character of s? How do we get at ALL THE REST of s? L = [ 21, 5, 16, 7 ] How do we get at the initial element of L? How do we get at ALL the REST of L? L[0]

Breaking Up… is easy to do with Python. s = "this has 2 t's"

Breaking Up… is easy to do with Python. s = "this has 2 t's" s[0] s[1: ] How do we get at the initial character of s? How do we get at ALL THE REST of s? L = [ 21, 5, 16, 7 ] L[0] L[1: ] How do we get at the initial element of L? How do we get at ALL the REST of L?

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters in s """

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters in s """ if s == '': return else: return

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters

Recursion Examples def mylen(s): """ input: any string, s output: the number of characters in s """ if s == '': return 0 else: return 1 + mylen( s[1: ] ) Will this work for lists?

Behind the curtain… mylen(‘eecs')

Behind the curtain… mylen(‘eecs')

Behind the curtain… mylen(‘eecs') 1 + mylen('ecs')

Behind the curtain… mylen(‘eecs') 1 + mylen('ecs')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('s')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('s')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('')

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('') = 0

Behind the curtain… mylen(‘eecs') 1 + mylen('cs') 1 + mylen('') = 0

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element """

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element """ if len(L) == 1: return else:

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element

Recursion Examples def mymax(L): """ input: a NONEMPTY list, L output: L's maximum element """ if len(L) == 1: return L[0] else: if L[0] < L[1]: return mymax( L[1: ] ) else: return mymax( L[0: 1] + L[2: ] )

mymax( [1, 7, 3, 42, 5] ) Behind the curtain…

mymax( [1, 7, 3, 42, 5] ) Behind the curtain…

"Quiz" on recursion def power(b, p): """ returns b to the p power using

"Quiz" on recursion def power(b, p): """ returns b to the p power using recursion, not ** inputs: ints b and p output: a float """ Handle negative values of p, as well. For example, power(5, -1) == 0. 2 def sajak(s): """ returns the number of vowels in the input string, s """ sajak('wheel of fortune') == 6 power(5, 2) == 25. 0 Want more power? Names: (or so)

def power(b, p): """ inputs: base b and power p (an int) implements: b**p

def power(b, p): """ inputs: base b and power p (an int) implements: b**p = b*b**(p-1) """ if p == 0: return if p > 0: return else: # p < 0 return

def power(b, p): """ inputs: base b and power p (an int) implements: b**p

def power(b, p): """ inputs: base b and power p (an int) implements: b**p = b*b**(p-1) """ if p == 0: return 1 if p > 0: return else: # p < 0 return

def power(b, p): """ inputs: base b and power p (an int) implements: b**p

def power(b, p): """ inputs: base b and power p (an int) implements: b**p = b*b**(p-1) """ if p == 0: return 1 if p > 0: return b*power(b, p-1) else: # p < 0 return

def power(b, p): """ inputs: base b and power p (an int) implements: b**p

def power(b, p): """ inputs: base b and power p (an int) implements: b**p = b*b**(p-1) """ if p == 0: return 1 if p > 0: return b*power(b, p-1) else: # p < 0 return 1/power(b, -1*p)

power(2, 3) behind the curtain

power(2, 3) behind the curtain

def sajak(s): Base case? when there are no letters, there are ZERO vowels Look

def sajak(s): Base case? when there are no letters, there are ZERO vowels Look at the initial character. Rec. step? if it is NOT a vowel, the answer is if it IS a vowel, the answer is

def sajak(s): Base case? when there are no letters, there are ZERO vowels Look

def sajak(s): Base case? when there are no letters, there are ZERO vowels Look at the initial character. Rec. step? if it is NOT a vowel, the answer is just the number of vowels in the rest of s if it IS a vowel, the answer is 1 + the number of vowels in the rest of s

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a vowel: Try #1

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a vowel: Try #1 and or not same as in English! but each side has to be a complete boolean value!

def sajak(s): if len(s) == 0: Base Case return 0 else: if s[0] ==

def sajak(s): if len(s) == 0: Base Case return 0 else: if s[0] == 'a' or s[0] == 'e' or… Checking for a vowel: Try #1 and or not same as in English! but each side has to be a complete boolean value!

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a

def sajak(s): if len(s) == 0: Base Case return 0 else: Checking for a vowel: Try #2 in

def sajak(s): if len(s) == 0: Base Case return 0 else: if s[0] not

def sajak(s): if len(s) == 0: Base Case return 0 else: if s[0] not in 'aeiou': Rec. Step return sajak(s[1: ]) else: if it is NOT a vowel, the answer is just the number of vowels in the rest of s return 1+sajak(s[1: ]) if it IS a vowel, the answer is 1 + the number of vowels in the rest of s

sajak('eerier') behind the curtain

sajak('eerier') behind the curtain

Good luck with Homework #1 The key to understanding recursion is to first understand

Good luck with Homework #1 The key to understanding recursion is to first understand recursion… - advice from a student