数据结构与算法(python版)之递归
一、什么是递归
1.递归定义
2.初识递归:数列求和
(1)问题:给定一个列表,返回所有数的和。假如没有循环语句,还能对不确定长度的列表求和吗?
(2)分析
(3)实现程序
def listSum(numList):
if len(numList)==1:
return numList[0]
else:
return numList[0]+listSum(numList[1:])
(4)递归程序如何被执行
3.递归三定律
二、递归的应用:十进制转换成任意进制
实现程序:
def baseConverterRe(n,base):
digits='0123456789ABCDEF'
if n<base:
return digits[n]
else:
return baseConverterRe(n//base,base)+digits[n%base]
print(baseConverterRe(156,16))
三、递归调用的实现
四、递归深度限制
五、递归可视化:分形树
1.python的海龟作图系统
图示程序:
import turtle
tPen=turtle.Turtle()
tPen.forward(100)
图示结果:
2.一个递归作图的例子:螺旋
(1)程序
tPen=turtle.Turtle()
def drawSpiral(t,lineLen):
if lineLen>0:
t.forward(lineLen)
t.right(90)
drawSpiral(t,lineLen-5)
drawSpiral(tPen,100)
(2)结果:
3.分型树
(1)什么是分型树
(2)分型树程序
import turtle
def tree(branch_len):
#树干太短不画,即递归结束推荐
if branch_len>5:
#画树干
t.forward(branch_len)
#右倾斜20度
t.right(20)
#递归调用,画右边的小树,树干减15
tree(branch_len-15)
#左倾斜40度
t.left(40)
#递归调用,画左边的小树,树干减15
tree(branch_len-15)
#向右回20度
t.right(20)
#海龟退回原位置
t.backward(branch_len)
t=turtle.Turtle()
t.left(90)
t.penup()
t.backward(100)
t.pendown()
t.pencolor('green')
t.pensize(2)
#画树干75的二叉树
tree(75)
t.hideturtle()
(3)分型树结果:
六、递归可视化:谢尔宾斯基三角形
1.谢尔宾斯基三角形
2.思路
3.实现程序
import turtle
#degree:阶数
#三角形的三个点
def sierpinski(degree,point):
colormap=['blue','red','green','white','yellow','orange']
drawTriangle(point,colormap[degree])
if degree>0:
#左下三角
sierpinski(degree-1,{'left':point['left'],'top':getMid(point['left'],point['top']),'right':getMid(point['left'],point['right'])})
#上三角
sierpinski(degree-1,{'left':getMid(point['left'],point['top']),'top':point['top'],'right':getMid(point['top'],point['right'])})
#右下三角
sierpinski(degree-1,{'left':getMid(point['left'],point['right']),'top':getMid(point['top'],point['right']),'right':point['right']})
def drawTriangle(points,color):
tP.fillcolor(color)
tP.penup()
tP.goto(points['top'])
tP.pendown()
tP.begin_fill()
tP.goto(points['left'])
tP.goto(points['right'])
tP.goto(points['top'])
tP.end_fill()
def getMid(p1,p2):
return ((p1[0]+p2[0])/2,(p1[1]+p2[1])/2)
tP=turtle.Turtle()
points={'left':(-200,-100),'top':(0,200),'right':(200,-100)}
sierpinski(5,points)
4.结果图
七、递归的应用:汉诺塔
1.问题
2.问题分解
3.问题分析
4.递归思路
5.实现程序
def moveTower(height,fromPole,withPole,toPole):
if height>=1:
moveTower(height-1,fromPole,toPole,withPole)
moveDisk(height,fromPole,toPole)
moveTower(height-1,withPole,fromPole,toPole)
def moveDisk(disk,fromPole,toPole):
print('Moving disk[{0}] from {1} to {2}'.format(disk,fromPole,toPole))
moveTower(3,"1#","2#","3#")
6.结果
八、递归的应用:探索迷宫
九、分治策略
十、优化问题和贪心策略
1.优化问题:
2.贪心策略
十一、找零兑换问题的递归解法
实现程序:
def recMC(coinValueList,change):
#初始化最少硬币数量,用最大值
minCoinCount=change
#最小规模结束条件
if change in coinValueList:
return 1
else:
for i in [coinV for coinV in coinValueList if coinV<=change]:
numCoinCount=1+recMC(coinValueList,change-i)
if numCoinCount<minCoinCount:
minCoinCount=numCoinCount
return minCoinCount
print(recMC([1,5,10,25],63))
改进程序:
def recDC(coinValueList,change,knownResults):
#初始化最少硬币数量,用最大值
minCoinCount=change
#最小规模结束条件
if change in coinValueList:
#记录最优解
knownResults[change]=1
return 1
elif knownResults[change]>0:
return knownResults[change]
else:
for i in [coinV for coinV in coinValueList if coinV<=change]:
numCoinCount=1+recDC(coinValueList,change-i,knownResults)
if numCoinCount<minCoinCount:
minCoinCount=numCoinCount
#找到最优解,记录到列表中
knownResults[change]=minCoinCount
return minCoinCount
print(recDC([1,5,10,25],63,[0]*64))
十二、找零兑换问题的动态规划解法
改进程序:
def dpMakeChange(coinValueList,change,minCoins):
#从1分开始到change逐个计算最少硬币个数
for cents in range(1,change+1):
#初始化最少硬币个数,用最大值
minCoinCount=cents
#减去每个硬币面值,向后查最少硬币数,同时记录总的最少数
for j in [coinV for coinV in coinValueList if coinV<=cents]:
numCoinCount=1+minCoins[cents-j]
if minCoinCount>numCoinCount:
minCoinCount=numCoinCount
#得到当前最小硬币数,记录到表中
minCoins[cents]=minCoinCount
#返回最后一个结果
return minCoins[change]
print(dpMakeChange([1,5,10,25],63,[0]*64))
扩展程序
def dpMakeChangeUsed(coinValueList,change,minCoins,coinsUsed):
#从1分开始到change逐个计算最少硬币个数
for cents in range(1,change+1):
#初始化最少硬币个数,用最大值
minCoinCount=cents
newCoin=1
#减去每个硬币面值,向后查最少硬币数,同时记录总的最少数
for j in [coinV for coinV in coinValueList if coinV<=cents]:
numCoinCount=1+minCoins[cents-j]
if minCoinCount>numCoinCount:
minCoinCount=numCoinCount
#记录本步骤新加的硬币
newCoin=j
#得到当前最小硬币数,记录到表中
minCoins[cents]=minCoinCount
# 记录新加的硬币
coinsUsed[cents]=newCoin
#返回最后一个结果
return minCoins[change],coinsUsed
def printUsedCoins(coinsUsed,change):
coin=change
while coin>0:
thisCoin=coinsUsed[coin]
print(thisCoin)
coin=coin-thisCoin
minCoinCount,coinsUsed=dpMakeChangeUsed([1,5,10,21,25],63,[0]*64,[0]*64)
print(minCoinCount)
printUsedCoins(coinsUsed,63)