数据结构与算法(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)

十三、动态规划案例分析

十四、小结

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值