Recursion - Hacettepe Üniversitesibbm101/fall15/lectures/... · 2015-11-19 · Recursion BBM 101...

Preview:

Citation preview

Recursion

BBM101- Introduction toProgramming I

Hacettepe UniversityFall2015

FuatAkal,AykutErdem,Erkut Erdem,Vahid Garousi

1Slides basedonmaterialpreparedbyE.Grimson, J.Guttag andC.Terman inMITx 6.00.1x,J.DeNero inCS61A(Berkeley)andR.Sedgewick,K.WayneandR.Dondero (Princeton)

Recursivefunctions

• Afunctioniscalledrecursive ifthebodyofthatfunctioncallsitself,eitherdirectlyorindirectly.

• Implication: Executingthebodyofarecursivefunctionmayrequireapplyingthatfunction

2

Recursive Functions

Definition: A function is called recursive if the body of that function calls itself, either directly or indirectly

Implication: Executing the body of a recursive function may require applying that function

Drawing Hands, by M. C. Escher (lithograph, 1948)4

Iterativealgorithms

• Loopingconstructs(e.g.whileorforloops)leadnaturallytoiterativealgorithms

• Canconceptualizeascapturingcomputationinasetof“statevariables”whichupdateoneachiterationthroughtheloop

3

Iterativemultiplicationbysuccessiveadditions

• Imaginewewanttoperformmultiplicationbysuccessiveadditions:– Tomultiplyabyb,addatoitselfbtimes

• Statevariables:– i – iterationnumber;startsatb– result– currentvalueofcomputation;startsat0

• Updaterules– i←i -1;stopwhen0– result ←result+a

4

Iterativemultiplicationbysuccessiveadditions

def iterMul(a, b): result = 0 while b > 0:

result += a b -= 1

return result

5

Recursiveversion

• Analternativeistothinkofthiscomputationas:

a*b=a+a+...+a

=a+a+...+a

=a+a*(b– 1)6

Recursive)version)

•  An)alterna0ve)is)to)think)of)this)computa0on)as:)

a)*)b)=)a)+)a)+)…)+)a)))

=)a)+)a)+)…)+)a)))

=)a)+)a)*)(b)–)1))

b)copies)

b@1)copies)

bcopies

Recursive)version)

•  An)alterna0ve)is)to)think)of)this)computa0on)as:)

a)*)b)=)a)+)a)+)…)+)a)))

=)a)+)a)+)…)+)a)))

=)a)+)a)*)(b)–)1))

b)copies)

b@1)copies)

b-1copies

Recursion

• Thisisaninstanceofarecursivealgorithm– Reduceaproblemtoasimpler(orsmaller)versionofthesameproblem,plussomesimplecomputations• Recursivestep

– Keepreducinguntilreachasimplecasethatcanbesolveddirectly• Basecase

• a*b=a;ifb=1(Basecase)• a*b=a+a*(b-1);otherwise(Recursivecase)

7

Recursivemultiplicationdef recurMul(a,b):

if b == 1: return a

else: return a + recurMul(a,b-1)

8

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

9

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

recurMul(2,3)

10

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul(2,&3)&

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

a& 2&

b& 3&

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

recurMul(2,3)

11

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul(2,&3)&

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

a& 2&

b& 3&

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

recurMul(2,3)

12

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul(2,&3)&

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

a& 2&

b& 3&

a& 2&

b& 2&

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul(2,&3)&

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

a& 2&

b& 3&

a& 2&

b& 2&

a& 2&

b& 1&

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

recurMul(2,3)

13

Let’s&try&it&out&def recurMul(a, b):! if b == 1:! return a! else:! return a + recurMul(a, b-1)!

!

recurMul(2,&3)&

recurMul& Procedure4&&&(a,&b)&&&&if&b&==&1:&&&&&&&&return&a&&&&else:&&&&&&&&return&a&+&recurMul(a,&b=1)&

a& 2&

b& 3&

a& 2&

b& 2&

a& 2&

b& 1&

4&

2&

6&

Let’stryitoutdef recurMul(a,b):

if b == 1: return a

else: return a +

recurMul(a,b-1)

recurMul(2,3)

14

TheAnatomyofaRecursiveFunction

15

def recurMul(a,b): if b == 1:

return a else: return a + recurMul(a,b-1)

• Thedef statementheaderissimilartootherfunctions

• Conditionalstatementscheckforbasecases• Basecasesareevaluatedwithoutrecursivecalls• Recursivecasesareevaluatedwithrecursivecalls

Inductivereasoning

• Howdoweknowthatourrecursivecodewillwork?

• iterMul terminatesbecausebisinitiallypositive,anddecreaseby1eachtimearoundloop;thusmusteventuallybecomelessthan1

• recurMul calledwithb=1hasnorecursivecallandstops

• recurMul calledwithb>1makesarecursivecallwithasmallerversionofb;musteventuallyreachcallwithb=1

16

Mathematicalinduction

• Toproveastatementindexedonintegersistrueforallvaluesofn:– Proveitistruewhennissmallestvalue(e.g.n=0orn=1)

– Thenprovethatifitistrueforanarbitraryvalueofn,onecanshowthatitmustbetrueforn+1

17

Example

• 0+1+2+3+...+n=(n(n+1))/2• Proof– Ifn=0,thenLHSis0andRHSis0*1/2=0,sotrue– Assumetrueforsomek,thenneedtoshowthat• 0+1+2+...+k+(k+1)=((k+1)(k+2))/2• LHSisk(k+1)/2+(k+1)byassumptionthatpropertyholdsforproblemofsizek• Thisbecomes,byalgebra,((k+1)(k+2))/2

– Henceexpressionholdsforalln>=0

18

Whatdoesthishavetodowithcode?

• Samelogicapplies

def recurMul(a, b): if b == 1:

return a else:

return a + recurMul(a, b-1)

• Basecase,wecanshowthatrecurMul mustreturncorrectanswer

• Forrecursivecase,wecanassumethatrecurMul correctlyreturnsananswerforproblemsofsizesmallerthanb,thenbytheadditionstep,itmustalsoreturnacorrectanswerforproblemofsizeb

• Thusbyinduction,codecorrectlyreturnsanswer19

Sumdigitsofanumber

20

Sum Digits Without a While Statement

6

def split(n):

"""Split positive n into all but its last digit and its last digit."""

return n // 10, n % 10

def sum_digits(n):

"""Return the sum of the digits of positive integer n."""

if n < 10:

return n

else:

all_but_last, last = split(n)

return sum_digits(all_but_last) + last

Verifythecorrectnessofthisrecursivedefinition.

Someobservations

• Eachrecursivecalltoafunctioncreatesitsownenvironment,withlocalscopingofvariables

• Bindingsforvariableineachframedistinct,andnotchangedbyrecursivecall

• Flowofcontrolwillpassbacktoearlierframeoncefunctioncallreturnsvalue

21

The“classic”recursiveproblem

• Factorialn! =n*(n-1)*...*1

=1 ifn=0n*(n-1)! otherwise

22

Recursive)version)

• An)alterna0ve)is)to)think)of)this)computa0on)as:)

a)*)b)=)a)+)a)+)…)+)a)))

=)a)+)a)+)…)+)a)))

=)a)+)a)*)(b)–)1))

b)copies)

b@1)copies)

RecursioninEnvironmentDiagrams

23

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

RecursioninEnvironmentDiagrams

24

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

RecursioninEnvironmentDiagrams

25

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

• Thesamefunctionfactiscalledmultipletimes

RecursioninEnvironmentDiagrams

26

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

• Thesamefunctionfactiscalledmultipletimes

• Differentframeskeeptrackofthedifferentargumentsineachcall

RecursioninEnvironmentDiagrams

27

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

• Thesamefunctionfactiscalledmultipletimes

• Differentframeskeeptrackofthedifferentargumentsineachcall

• Whatnevaluatestodependsuponthecurrentenvironment

RecursioninEnvironmentDiagrams

28

Recursion in Environment Diagrams

9

(Demo)

Interactive Diagram

• Thesamefunctionfactiscalledmultipletimes

• Differentframeskeeptrackofthedifferentargumentsineachcall

• Whatnevaluatestodependsuponthecurrentenvironment

• Eachcalltofactsolvesasimplerproblemthanthelast:smallern

IterationvsRecursion

29

4! = 4 · 3 · 2 · 1 = 24

n! =nY

k=1

k n! =

(1 if n = 0

n · (n� 1)! otherwise

Iteration vs Recursion

Iteration is a special case of recursion

def fact_iter(n): total, k = 1, 1 while k <= n: total, k = total*k, k+1 return total

def fact(n): if n == 0: return 1 else: return n * fact(n-1)

Using while: Using recursion:

n, total, k, fact_iter

Math:

Names:

10

IterationvsRecursion

30

4! = 4 · 3 · 2 · 1 = 24

n! =nY

k=1

k n! =

(1 if n = 0

n · (n� 1)! otherwise

Iteration vs Recursion

Iteration is a special case of recursion

def fact_iter(n): total, k = 1, 1 while k <= n: total, k = total*k, k+1 return total

def fact(n): if n == 0: return 1 else: return n * fact(n-1)

Using while: Using recursion:

n, total, k, fact_iter

Math:

Names:

10

4! = 4 · 3 · 2 · 1 = 24

n! =nY

k=1

k n! =

(1 if n = 0

n · (n� 1)! otherwise

Iteration vs Recursion

Iteration is a special case of recursion

def fact_iter(n): total, k = 1, 1 while k <= n: total, k = total*k, k+1 return total

def fact(n): if n == 0: return 1 else: return n * fact(n-1)

Using while: Using recursion:

n, total, k, fact_iter

Math:

Names: n, fact

10

IterationvsRecursion

31

4! = 4 · 3 · 2 · 1 = 24

n! =nY

k=1

k n! =

(1 if n = 0

n · (n� 1)! otherwise

Iteration vs Recursion

Iteration is a special case of recursion

def fact_iter(n): total, k = 1, 1 while k <= n: total, k = total*k, k+1 return total

def fact(n): if n == 0: return 1 else: return n * fact(n-1)

Using while: Using recursion:

n, total, k, fact_iter

Math:

Names: n, fact

10

4! = 4 · 3 · 2 · 1 = 24

n! =nY

k=1

k n! =

(1 if n = 0

n · (n� 1)! otherwise

Iteration vs Recursion

Iteration is a special case of recursion

def fact_iter(n): total, k = 1, 1 while k <= n: total, k = total*k, k+1 return total

def fact(n): if n == 0: return 1 else: return n * fact(n-1)

Using while: Using recursion:

n, total, k, fact_iter

Math:

Names:

10

Recursiononnon-numerics

• Howcouldwecheckwhetherastringofcharactersisapalindrome,i.e.,readsthesameforwardsandbackwards– “AblewasIereIsawElba”– attributedtoNapolean

– “Arewenotdrawnonward,wefew,drawnonwardtonewera?”

32

Howtowesolvethisrecursive?

• First,convertthestringtojustcharacters,bystrippingoutpunctuation,andconvertinguppercasetolowercase

• Then– Basecase:astringoflength0or1isapalindrome– Recursivecase:• Iffirstcharactermatcheslastcharacter,thenisapalindromeifmiddlesectionisapalindrome

33

Example

• ‘AblewasIereIsawElba’à‘ablewasiereisawleba’

• isPalindrome(‘ablewasiereisawleba’)issameas– ‘a’==‘a’andisPalindrome(‘blewasiereisawleb’)

34

Palindromeornot?def toChars(s):

s = s.lower() ans = '' for c in s:

if c in 'abcdefghijklmnopqrstuvwxyz': ans = ans + c

return ans

def isPal(s): if len(s) <= 1:

return True else:

return s[0] == s[-1] and isPal(s[1:-1])

def isPalindrome(s):return isPal(toChars(s)) 35

Divideandconquer

• Thisisanexampleofa“divideandconquer”algorithm– Solveahardproblembybreakingitintoasetofsub-problemssuchthat:

– Sub-problemsareeasiertosolvethantheoriginal– Solutionsofthesub-problemscanbecombinedtosolvetheoriginal

36

Globalvariables

• Supposewewantedtocountthenumberoftimesfibcallsitselfrecursively

• Candothisusingaglobalvariable• Sofar,allfunctionscommunicatewiththeirenvironmentthroughtheirparametersandreturnvalues

• But,(thoughabitdangerous),candeclareavariabletobeglobal– meansnameisdefinedattheoutermostscopeoftheprogram,ratherthanscopeoffunctioninwhichappears

37

Exampledef fibMetered(x):

global numCallsnumCalls += 1 if x == 0 or x == 1:

return 1 else:

return fibMetered(x-1) + fibMetered(x-2)

def testFib(n): for i in range(n+1):

global numCallsnumCalls = 0 print('fib of ' + str(i) + ' = ' + str(fibMetered(i))) print('fib called ' + str(numCalls) + ' times')

38

Globalvariables

• Usewithcare!!• Destroylocalityofcode• Sincecanbemodifiedorreadinawiderangeofplaces,canbeeasytobreaklocalityandintroducebugs!!

39

Mutualrecursion

• Mutualrecursion isaformofrecursion wheretwofunctionsordatatypesare defined intermsofeachother.

40

TheLuhn Algorithm• Asimplechecksumformulausedtovalidateavarietyofidentification

numbers,suchascreditcardnumbers,IMEInumbers,etc.

41

TheLuhn Algorithm• FromWikipedia:http://en.wikipedia.org/wiki/Luhn_algorithm• First:Fromtherightmostdigit,whichisthecheckdigit,movingleft,

doublethevalueofeveryseconddigit;ifproductofthisdoublingoperationisgreaterthan9(e.g.,7*2=14),thensumthedigitsoftheproducts(e.g.,10:1+0=1,14:1+4=5)

• Second:Takethesumofallthedigits

• TheLuhn sumofavalidcreditcardnumberisamultipleof10

42

The Luhn Algorithm

Used to verify credit card numbers

From Wikipedia: http://en.wikipedia.org/wiki/Luhn_algorithm

• First: From the rightmost digit, which is the check digit, moving left, double the value of every second digit; if product of this doubling operation is greater than 9 (e.g., 7 * 2 = 14), then sum the digits of the products (e.g., 10: 1 + 0 = 1, 14: 1 + 4 = 5)

• Second: Take the sum of all the digits

15

1 3 8 7 4 3

2 3 1+6=7 7 8 3 = 30

TheLuhn Algorithmdef luhn_sum(n):

“""Return the digit sum of n computed by the Luhn algorithm""" if n < 10:

return nelse:

all_but_last, last = split(n)return luhn_sum_double(all_but_last) + last

def luhn_sum_double(n): """Return the Luhn sum of n, doubling the last digit."""

all_but_last, last = split(n) luhn_digit = sum_digits(2 * last) if n < 10:

return luhn_digitelse:

return luhn_sum(all_but_last) + luhn_digit

43

TreeRecursion

• Tree-shapedprocessesarisewheneverexecutingthebodyofarecursivefunctionmakesmorethanonerecursivecall.

44

TreeRecursion• Fibonaccinumbers• LeonardoofPisa(akaFibonacci)modeledthefollowingchallenge– Newbornpairofrabbits(onefemale,onemale)areputinapen

– Rabbitsmateatageofonemonth– Rabbitshaveaonemonthgestationperiod– Assumerabbitsneverdie,thatfemalealwaysproducesonenewpair(onemale,onefemale)everymonthfromitssecondmonthon.

– Howmanyfemalerabbitsarethereattheendofoneyear?

45

Fibonacci

• Afteronemonth(callit0)– 1female• Aftersecondmonth– still1female

(nowpregnant)• Afterthirdmonth– twofemales,one

pregnant,onenot• Ingeneral,females(n)=females(n-1)+

females(n-2)– Everyfemalealiveatmonthn-2will

produceonefemaleinmonthn;– Thesecanbeaddedthosealiveinmonth

n-1togettotalaliveinmonthn

46

Fibonacci*•  AEer*one*month*(call*it*0)*–*1*female*•  AEer*second*month*–*s0ll*1*female*

(now*pregnant)*•  AEer*third*month*–*two*females,*one*

pregnant,*one*not*•  In*general,*females(n)*=*females(nK1)*+*

females(nK2)*–  Every*female*alive*at*month*nK2*will*produce*one*female*in*month*n;*

–  These*can*be*added*those*alive*in*month*nK1*to*get*total*alive*in*month*n*

Month* Females*

0* 1*

1* 1*

2* 2*

3* 3*

4* 5*

5* 8*

6* 13*

Fibonacci

• Basecases:– Females(0)=1– Females(1)=1

• Recursivecase– Females(n)=Females(n-1)+Females(n-2)

47

Fibonaccidef fib(n):

"""assumes n an int >= 0 returns Fibonacci of n""" assert type(n) == int and n >= 0 if n == 0:

return 1 elif n == 1:

return 1 else:

return fib(n-2) + fib(n-1)

48

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

49

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

50

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

51

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

52

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

53

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

54

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

55

A Tree-Recursive Process

The computational process of fib evolves into a tree structure

11

fib(5)

fib(4)

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

Atree-recursiveprocess• Thecomputationalprocessoffibevolvesintoatreestructure

56

PitfallsofRecursion

• Withrecursion,youcancomposecompactandelegantprogramsthatfailspectacularlyatruntime.

• Missingbasecase• Noguarentee ofconvergence• Excessivespacerequirements• Excessiverecomputation

57

Missingbasecasedef H(n):

return H(n-1) + 1.0/n;

• ThisrecursivefunctionissupposedtocomputeHarmonicnumbers,butismissingabasecase.

• Ifyoucallthisfunction,itwillrepeatedlycallitselfandneverreturn.

58

Noguaranteeofconvergencedef H(n):

if n == 1: return 1.0

return H(n) + 1.0/n

• Thisrecursivefunctionwillgointoaninfiniterecursiveloopifitisinvokedwithanargumentnhavinganyvalueotherthan1.

• Anothercommonproblemistoincludewithinarecursivefunctionarecursivecalltosolveasubproblem thatisnotsmaller.

59

Excessivespacerequirements• Pythonneedstokeeptrackofeachrecursivecalltoimplement

thefunctionabstractionasexpected.• Ifafunctioncallsitselfrecursivelyanexcessivenumberoftimes

beforereturning,thespacerequiredbyPythonforthistaskmaybeprohibitive.

def H(n): if n == 0:

return 0.0 return H(n-1) + 1.0/n

• Thisrecursivefunctioncorrectlycomputesthenthharmonicnumber.

• However,wecannotuseitforlarge n becausetherecursivedepthisproportionalto n,andthiscreatesa StackOverflowError.

60

Excessiverecomputation• A simplerecursiveprogrammightrequireexponentialtime

(unnecessarily),duetoexcessiverecomputation.• Forexample,fibiscalledonthesameargumentmultiple

times

61

Repetition in Tree-Recursive Computation

fib(5)

fib(3)

fib(1)

1

fib(4)

fib(2)

fib(0) fib(1)

0 1

fib(2)

fib(0) fib(1)

0 1

fib(3)

fib(1)

1

fib(2)

fib(0) fib(1)

0 1

This process is highly repetitive; fib is called on the same argument multiple times

12

RecursiveGraphics• Simplerecursivedrawingschemescanleadtopicturesthat

areremarkablyintricate– Fractals• Forexample,an H-treeofordern isdefinedasfollows:

– Thebasecaseisnullforn =0.– Thereductionstepistodraw,withintheunitsquarethreelinesinthe

shapeoftheletterHfourH-treesofordern-1.– OneconnectedtoeachtipoftheHwiththeadditionalprovisosthat

theH-treesoforder n-1arecenteredinthefourquadrantsofthesquare,halvedinsize.

62

Morerecursivegraphics

63

• Sierpinski triangles

• Recursivetrees

Recommended