3递归(上)——数据结构与算法Python版学习笔记

什么是递归Recursion?

递归是一种解决问题的方法,其精髓在于

  • 将问题分解成规模更小的相同问题
  • 持续分解,直到问题规模小到可以用非常简单直接的方式来解决
  • 递归的问题分解方式非常独特,其算法方面明显特征就是:在算法流程中调用自身。

例如,
不确定长度的列表求和

#方法1
def listsum(numList):
	theSum = 0
	for i in numList:
		theSum = theSum + i
	return theSum
#方法2
def listsum(numList):
	if len(numList) == 1:
		return numList[0]
	else:
		return numList[0] + listsum(numList[1:])
print(listsum([1,3,5,7,9]))
	

在这里插入图片描述
递归“三定律”
1.递归算法必须有一个基本结束条件(最小规模问题的直接解决)

列表长度为1时,世界输出所包含的唯一数

2.递归算法必须能改变状态向基本结束条件演进(减小问题规模)

每次提出1个数,向长度为1的状态演进

3.递归算法必须调用自身(解决减小了规模的相同问题)

并不需要搞得那么清楚,就是相同问题的解决

递归的引用:任意进制转换

在这里插入图片描述

def toStr(n,base):
    convertString = '0123456789ABCDEF'
    if n < base:
        return convertString[n]
    else:
        return toStr(n//base,base) + convertString[n%base]
print(toStr(1453,16))

在这里插入图片描述
递归调用的实现

当一个函数被调用的时候,系统会把调用时的现场数据压入系统调用栈
每次调用,压入栈的现场数据称为栈帧
当函数返回时,要从调用栈顶取得返回地址,恢复现场,弹出栈帧,按地址返回。

Python中的递归深度限制

RecursionError:递归的层数太多,系统调用栈容量有限
这时候要检查程序中是否忘记设置基本结束条件,导致无限递归,或者向基本结束条件演进太慢,导致递归层数太多,调用栈移除。

在Python内置的sys模块可以获取和调整最大递归深度
import sys
sys.getrecursionlimit()

1000

sys.setrecursionlimit(3000)
sys.getrecursionlimit()

3000

递归可视化:分形树

一个递归作图的例子:螺旋
在这里插入图片描述

import turtle
t = turtle.Turtle()
def drawSpiral(t,lineLen):
    if lineLen > 0:
        t.forward(lineLen)
        t.right(90)
        drawSpiral(t,lineLen - 5)
drawSpiral(t,100)
turtle.done()

可以简单的理解为Turtle ()函数创建了一个对象,这个对象就是p,然后你利用了对象p的方法如speed()、pensize()等

为了体会turtle.Turtle(),自我感觉是决定了乌龟的起点,如果在函数里面将多次调用使得乌龟每次都落回起点上
在这里插入图片描述
在这里插入图片描述
所以这样写在函数前就可以了在这里插入图片描述

分形树:自相似递归图形

自相似性质:一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分(至少近似地)是整体缩小后的形状

在这里插入图片描述

import turtle
def tree(branch_len):
    if branch_len > 5:#树干太短不画,即递归结束条件
        t.forward(branch_len)#画树干
        t.right(20)#右倾斜20度
        tree(branch_len - 15)#递归调用,画右边的小树,树干减15
        t.left(40)#左回40度,即左倾斜20度
        tree(branch_len - 15)#递归调用,画左边的小树,树干减15
        t.right(20)#向右20度,即回正
        t.backward(branch_len)#海龟退回原位置
t = turtle.Turtle()
t.left(90)
t.penup()
t.backward(100)
t.pendown()
t.pencolor('green')
t.pensize(2)
tree(75)#画树干长度72的二叉树
t.hideturtle()
turtle.done()

递归可视化:谢尔宾斯基三角形

谢尔宾斯基三角形是由3个尺寸减半的谢尔宾斯基三角形按照品字形拼叠而成
我们无法真正做出谢尔宾斯基三角形(degree->无穷),只能做degree有限的近似图形

在这里插入图片描述

import turtle
def sierpinski(degree,points):
    colormap = ['blue','red','green','white','yellow','orange']
    drawTriangle(points,colormap[degree])#等边三角形
    if degree > 0:#最小规模,0直接退出
    #减小规模:getMid边长减半,调用自身左上右次序
        sierpinski(degree -1,
                   {'left':points['left'],
                    'top':getMid(points['left'],points['top']),
                    'right':getMid(points['left'],points['right'])})
        sierpinski(degree - 1,
                    {'left':getMid(points['left'],points['top']),
                    'top':points['top'],
                    'right':getMid(points['top'],points['right'])})
        sierpinski(degree - 1,
                   {'left':getMid(points['left'],points['right']),
                    'top':getMid(points['top'],points['right']),
                    'right':points['right']})
#绘制deng'bian'san'j等边三角形                
def drawTriangle(points,color):
    t.fillcolor(color)
    t.penup()
    t.goto(points['top'])
    t.pendown()
    t.begin_fill()
    t.goto(points['left'])
    t.goto(points['right'])
    t.goto(points['top'])
    t.end_fill()
#取两个点的中点    
def getMid(p1,p2):
    return ((p1[0] + p2[0])a / 2,(p1[1] + p2[1]) /2 )
t = turtle.Turtle()
#外轮廓三个顶点
points = {'left':(-200,-100),
          'top':(0,200),
          'right':(200,-100)}
sierpinski(5,points)#画degree = 5的三角形
turtle.done()

递归的应用:汉诺塔

在这里插入图片描述
分解为递归形式:

假设我们有5个盘子,穿在1#柱,需要挪到3#柱
如果能有办法把最上面的一摞4个盘子统统挪到2#
把剩下的最大号盘子直接从1#柱挪到2#柱
再把2#柱上的一摞4个盘子挪到3#柱,就完成了整个移动
接下来的问题就是解决4个盘子如何能从1#挪到2#?
同样是想办法把上面的一摞3个盘子挪到3#柱,
把剩下最大号盘子从1#挪到2#柱
再把一摞3个盘子从3#挪到2#柱
一摞3个盘子的挪动也照此:
分为上面一摞2个,和下面最大号盘子

递归思路

将盘片塔从开始柱,经由中间柱,移动到目标柱:

  • 首先将上层N-1个盘片的盘片塔,柱从开始柱,经由目标,移动到中间柱;
  • 然后将第N个(最大的)盘片,从开始柱,移动到目标柱;
  • 最后将放置在中间柱的N-1个盘片的盘片塔,经由开始柱,移动到目标柱

基本结束条件,也就是最小规模问题是:1个盘片的移动问题

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(f"Moving disk[{disk}] from {fromPole} to {toPole}")
moveTower(3,'#1','#2','#3')

在这里插入图片描述
值得学习的:函数命名可以具体一点,print参数

递归的应用:探索迷宫

将海龟放在迷宫中间,如何能找到出口?

首先,我们将整个迷宫的空间(矩形)分为行列整齐的方格,区分出墙壁和通道
考虑用矩阵方式来实现迷宫数据结构,采用“数据项为字符列表的列表”这种两级列表的方式来保存方格内容

详解请看大爽歌博客
点击观看配套B站视频(记得点赞投币哟)
在这里插入图片描述
STEP1:准备工作在这里插入图片描述
STEP2:提取txt迷宫信息到列表里来
在这里插入图片描述
STEP3:根据迷宫信息绘制迷宫
分步1:定义画墙函数
坐标计算如图
在这里插入图片描述
在这里插入图片描述
分步2:定义画点函数
在这里插入图片描述
分布3:画迷宫
在这里插入图片描述
在这里插入图片描述
STEP4:核心——递归方法探索
分步1:定义画路径函数
在这里插入图片描述
分步2:建立探索规则
在这里插入图片描述
分步3:下一步(该点四个方向)调用自身
在这里插入图片描述
STEP5:找到起点初始化
在这里插入图片描述
STEP6:调用函数
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值