Ceng2001 Week6
Ceng2001 Week6
"Droste effect 1260359-3" by Nevit Dilmen (talk) - Own work. Licensed under CC BY-SA 3.0 via
Wikimedia Commons -
https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/Droste_1260359-
nevit.jpg/1280px-Droste_1260359-nevit.jpg
For example, we can define the operation
"find your way home" as:
def countDown(n):
while n > 0:
print(n)
n = n - 1
Python example (recursive)
• count down from some number n to 1
def countDown(n):
print( n )
if n > 1:
countdown( n-1 )
book example: sum a list
• sum list of numbers [ 2, 5, 10 ]
• Think about + works on two operands
• so you can add the first item on list to the sum of
the rest of the list
• i.e. we get this sequence
• sum( [2, 5, 10]) = 2 + sum of [5, 10 ]
• sum( [ 5, 10] ) = 5 + sum( [ 10 ])
• sum( [ 10 ] ) = 10 + sum( [ ] )
• we can have sum of empty list return 0
python book example (modified)
def sum_list(a_list):
if len(a_list) == 0: # empty
return 0
return a_list[0] +
sum_list(a_list[1:])
Three Laws of Recursion
like the robots of Asimov, recursion must follow 3 laws
def sum_list(a_list):
if len(a_list) == 0: # empty
return 0
item1 = a_list[0]
rest = sum_list(a_list[1:])
return item1 + rest
total = sum_list([ 1, 3, 5, 7 ])
sum([1,3,5,7]
)
= 1+
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+
sum([7]) = 7+
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+
sum([7]) = 7+
sum([]) = 0
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+
sum([7]) = 7+
sum([]) = 0
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+
sum([7]) = 7+ 0
sum([]) = 0
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3+
sum([5,7]) = 5+ 7
sum([7]) = 7+ 0
sum([]) = 0
sum([1,3,5,7]
)
= 1+
sum([3,5,7]) = 3 + 12
sum([5,7]) = 5+ 7
sum([7]) = 7+ 0
sum([]) = 0
sum([1,3,5,7]
)
= 1 + 15
sum([3,5,7]) = 3 + 12
sum([5,7]) = 5+ 7
sum([7]) = 7+ 0
sum([]) = 0
sum([1,3,5,7]
)
= 1 + 15 16
sum([3,5,7]) = 3 + 12
sum([5,7]) = 5+ 7
sum([7]) = 7+ 0
sum([]) = 0
Converting a Number to a string
representation of any base
Same problem as in chapter 3 that
used a stack, but we will use
recursion
How we are going to do it
• look at base 10 and the number 769
• suppose we have convStr = '0123456789'
• Its easy to convert any number n less than 10,
it is just convStr[n] – our base case
• Now if we can work toward the base case, by
peeling a number off the original, we can use
recursion
• Well we can use n // 10 and n % 10 to get the
original 769 into 76 and 9
now we can use base
• what works with base 10 will work with base 2
to 16, we just use n // base and n % base to
split off one digit and expand our lookup
string to "0123456789ABCDEF"
the code
def toStr(n,base):
digits = '0123456789ABCDEF'
if n < base:
return digits[n]
return toStr(n // base,base)
+ digits[n % base]
Using recursion to draw things
turtle graphics
what is turtle graphics
• simple drawing for kids
• invented in late 60s
• popular in a OOP language called logo
• Imagine a turtle, that has a tail that can paint
a color in the path of the turtle as it moves.
• It follows very simple commands to turn left
or right a number of degrees
• to raise or lower its tail to draw.
• And you can tell it to move forward so many
steps or backward so many steps
Initial turtle direction and position
+y
-y
t.forward(50)
t.right(90)
t.forward(50)
t.color("red")
t.left(45)
t.backward(50)
t.right(90)
t.up()
t.forward(10)
t.down()
t.forward(10)
t.up()
t.forward(10)
t.down()
t.forward(10)
code to set up drawing and close
import turtle
def tree(branchLen,t):
if branchLen > 5:
t.forward(branchLen)
t.right(20)
tree(branchLen-15,t) # recurse next branch 15 shorter
t.left(40)
tree(branchLen-15,t) # recurse next branch 15 shorter
t.right(20) # return to start direction
t.backward(branchLen) # back down branch same to start pos
def main():
t = turtle.Turtle()
myWin = turtle.Screen()
t.left(90)
t.up()
t.backward(100)
t.down() # now at base of tree
t.color("green") # set color of tree start
tree(75,t) # draw tree starting at 75 length branches
myWin.exitonclick()
main()
Use the debugger
Step over – execute this line but do not go into any methods
Sierpinski Triangle
c a
p3 p2
b
p1
c a
p3 p2
b
p1
c a
p3 p2
b
p1
c a
p3 p2
b
Look at code for Siepinski
Triangle
Towers of Hanoi
if maze[startRow][startColumn] == OBSTACLE :
return False
if maze[startRow][startColumn] == TRIED
or maze[startRow][startColumn] == DEAD_END:
return False # We have found a square that has already been explored
• Answer is 6 coins
2 Quarters + 1 dime + 3 pennies
25 + 25 + 10 + 1 + 1 + 1 = 68
minimum for 63 cents
• This method of starting with the biggest coin
first, use all quarters and then all dimes, and
then all nickels and finally pennies called the
greedy algorithm approach
• Try to solve a big part of the problem right
away. (using the largest coin)
– it works for American coins but what about the
imaginary country: Lower Elbonia where they
have coins for 1, 5, 10, 25 and a special 21 cent
piece.
21
cent
• With the extra 21 cent piece our algorithm will
not work. We would still have a 6 coin solution.
by picking the largest coins: 25 + 25 we would
then have 13 cents left, so next we would pick
the dime, we would have 3 cents left and we
would pick a nickel and three pennies.
• But with the 21 cent piece available we can just
choose to pay with three 21 cent pieces = 63
cents
Our Recursive Solution
• Each recursive step we try each possible coin:
25, 21, 10, 5 and 1
And then pick the one with the minimum number of coins for
the smaller problem:
1 + minChange(amt-1)
1 + minChange(amt-5)
minChange(amt)= min of 1 + minChange(amt-10)
1 + minChange(amt-21)
1 + minChange(amt-25)
code:
def minChange(coinValueList,change):
minCoins = change
if change in coinValueList:
return 1
else:
for i in [c for c in coinValueList if c <= change]:
numCoins = 1 + minChange(coinValueList,change-i)
if numCoins < minCoins:
minCoins = numCoins
return minCoins
print(minChange([1,5,10,25],63))
Why does it take so long
• it turns out this code is very slow. It will take over
a minute to run
• try it, but be patient
• It requires 67,716,925 recursive calls to solve the
63 cent change problem with American money.
Lets look at the top of the call chart for solving for
making 26 cents in change, which takes 377 calls:
Note: blue numbers are the coin value subtracted, number
in circle represents recursive call value
step 1
step 2
step 3
step 4
step 5
step 6
step 7
Step 11, each step has to find best
solution for each coin
A penny plus the minimum number of coins to make change for 11−1=10 cents (1)
A nickel plus the minimum number of coins to make change for 11−5=6 cents (2)
A dime plus the minimum number of coins to make change for 11−10=1 cent (1)