The problem
def rangeSum(lo, hi):
if (lo > hi):
return 0
else:
return lo + rangeSum(lo+1, hi)
print(rangeSum(1,1234)) # RuntimeError: maximum recursion depth exceeded
The solution (on most platforms):
def rangeSum(lo, hi):
if (lo > hi):
return 0
else:
return lo + rangeSum(lo+1, hi)
def callWithLargeStack(f,*args):
import sys
import threading
threading.stack_size(2**27) # 64MB stack
sys.setrecursionlimit(2**27) # will hit 64MB stack limit first
# need new thread to get the redefined stack size
def wrappedFn(resultWrapper): resultWrapper[0] = f(*args)
resultWrapper = [None]
#thread = threading.Thread(target=f, args=args)
thread = threading.Thread(target=wrappedFn, args=[resultWrapper])
thread.start()
thread.join()
return resultWrapper[0]
print(callWithLargeStack(rangeSum,1,123456)) # prints 7620753696
The "solution" (on some Macs):
def rangeSum(lo, hi):
if (lo > hi):
return 0
else:
return lo + rangeSum(lo+1, hi)
def callWithLargeStack(f,*args):
import sys
import threading
sys.setrecursionlimit(2**14) # max recursion depth of 16384
isWindows = (sys.platform.lower() in ["win32", "cygwin"])
if (not isWindows): return f(*args) # sadness...
threading.stack_size(2**27) # 64MB stack
# need new thread to get the redefined stack size
def wrappedFn(resultWrapper): resultWrapper[0] = f(*args)
resultWrapper = [None]
#thread = threading.Thread(target=f, args=args)
thread = threading.Thread(target=wrappedFn, args=[resultWrapper])
thread.start()
thread.join()
return resultWrapper[0]
print(callWithLargeStack(rangeSum,1,123456)) # prints 7620753696
2. Improving Efficiency with Memoization
The problem
def fib(n):
if (n < 2):
return 1
else:
return fib(n-1) + fib(n-2)
import time
def testFib(maxN=40):
for n in range(maxN+1):
start = time.time()
fibOfN = fib(n)
ms = 1000*(time.time() - start)
print("fib(%2d) = %8d, time =%5dms" % (n, fibOfN, ms))
testFib() # gets really slow!
The solution
ibResults = dict()
def fib(n):
if (n in fibResults):
return fibResults[n]
if (n < 2):
result = 1
else:
result = fib(n-1) + fib(n-2)
fibResults[n] = result
return result
import time
def testFib(maxN=40):
for n in range(maxN+1):
start = time.time()
fibOfN = fib(n)
ms = 1000*(time.time() - start)
print("fib(%2d) = %8d, time =%5dms" % (n, fibOfN, ms))
testFib() # ahhh, much better!
3. Advanced Worked Examples Using Recursion
1. powerset (all subsets)
def powerset(a):
# returns a list of all subsets of the list a
if (len(a) == 0):
return [[]]
else:
allSubsets = [ ]
for subset in powerset(a[1:]):
allSubsets += [subset]
allSubsets += [[a[0]] + subset]
return allSubsets
print(powerset([1,2,3]))
2. permutations
def permutations(a):
# returns a list of all permutations of the list a
if (len(a) == 0):
return [[]]
else:
allPerms = [ ]
for subPermutation in permutations(a[1:]):
for i in range(len(subPermutation)+1):
allPerms += [subPermutation[:i] + [a[0]] + subPermutation[i:]]
return allPerms
print(permutations([1,2,3]))
3. printFiles (with os module)
To test this, download and expand this zip file in the same directory
as the Python file you are running:
sampleFiles.zip
import os
def printFiles(path):
if (os.path.isdir(path) == False):
# base case: not a folder, but a file, so print its path
print(path)
else:
# recursive case: it's a folder
for filename in os.listdir(path):
printFiles(path + "/" + filename)
printFiles("sampleFiles")
4. listFiles (with os module)
To test this, download and expand this zip file in the same directory
as the Python file you are running:
sampleFiles.zip
import os
def listFiles(path):
if (os.path.isdir(path) == False):
# base case: not a folder, but a file, so return singleton list with its path
return [path]
else:
# recursive case: it's a folder, return list of all paths
files = [ ]
for filename in os.listdir(path):
files += listFiles(path + "/" + filename)
return files
print(listFiles("sampleFiles"))
4. Fractals
1. sierpinskiTriangle (with Tkinter)
Key excerpt:
def drawSierpinskyTriangle(canvas, x, y, size, level):
# (x,y) is the lower-left corner of the triangle
# size is the length of a side
if (level == 0):
canvas.create_polygon(x, y,
x+size, y,
x+size/2, y-size*(3**0.5)/2,
fill="black")
else:
drawSierpinskyTriangle(canvas, x, y, size/2, level-1)
drawSierpinskyTriangle(canvas, x+size/2, y, size/2, level-1)
drawSierpinskyTriangle(canvas, x+size/4, y-size*(3**0.5)/4, size/2, level-1)