基于python的数据结构和算法(北京大学)第五章(递归)
此章理解较为困难,未写自写代码,仅仅记录标准代码并复现。
-
什么是递归(Recursion)
递归是一种解决问题的方法,其精髓在于将问题分解为规模更小的相同问题。持续分解,直到问题规模小到可以用非常简单直接的方式来解决。递归的问题分解方法非常独特,其算法方面的明显特征就是:在算法流程中调用自身。 -
递归的三定律:
1.递归算法必须有一个基本结束条件(最小规模问题的直接解决)
2.递归算法必须能改变状态向基本结束条件演进(减小问题规模)
3.递归算法必须调用自身(解决减小了规模的相同问题) -
初识递归:数列求和
算法思路:数列的和 = 首个数 + 余下数列的和 ,如果数列包含的数少到只有1个的话,它的和就是这个数了。
代码实现:
def ListSum(alist): if len(alist) == 1: return alist[0] else: return alist[0] + ListSum(alist[1 : ]) print(ListSum([1,3,5,7,9]))
根据递归的“三定律”来分析下数列求和问题:
1.数列求和问题首先具备了基本结束条件:当列表长度为1的时候,直接输出所包含的唯一数。
2.数列求和处理的数据对象是一个列表,而基本结束条件是长度为1的列表,那递归算法就要改变列表并向长度为1的状态演进。(具体做法为将列表长度减1)
3.调用自身:在数列求和算法中就是”更短数列的求和问题“
- 递归版本的任意数制转换:
算法思路:
1.假设是要转换为十进制,比十小的整数转换为十进制,直接查表就可以得到,比十大的整数就想办法拆成一系列比十小的整数,逐个查表。
2.所以递归基本结束条件就是小于十的整数,拆解整数的过程就是向基本结束条件演进的过程。
3.拆解过程分为两步:1. 除以“进制基base” (// base);2. 对“进制基”求余数(% base)。
4.此时问题就分解为:1. 余数总小于“进制基base”,是基本结束条件,可直接查表转换;2. 整数商成为更小规模问题,通过递归调用自身解决。
代码实现:
def toStr(n,base): constring = '0123456789ABCDEF' if n < base: return constring else: return toStr(n//base,base) + constring(n % base)
注意点为 return toStr(n//base,base) + constring(n % base)此语句,因为取余数之后要”倒“写结果(最先得到的余数放在最后面)所以根据递归过程,要把进入递归的”入口“写在得到余数的前面。
- 递归调用的实现:
在python中递归深度有限制:
def tell_story(): print("从前有座山,山上有座庙,庙里有个老和尚,他在讲:”) tell_story() print("给你讲个故事") tell_story()
这时候要检查程序中是否忘记设计基本结束条件,导致无限递归。或者向基本技术条件的演进太慢,导致递归层数太多,调用栈溢出。
-
python中的递归深度限制:
-
递归的可视化:图示
代码实现:
import turtle # 正方形: t = turtle.Turtle() for i in range(4): t.towards(100) t.right(90) turtle.done() # 五角星: t = turtle.Turtle() t.pencolor("red") t.pensize(3) for i in range(5): t.towards(100) t.right(144) t.hideturtle() turtle.done() # 螺旋线: t = turtle.Turtle() def drawSpiral(t,lineLen): if lineLen > 0: t.forward(lineLen) t.right(90) drawSpiral(t,lineLen-5) drawSpiral(t,200) turtle.done()
- 分形树:自相似递归图形问题:
分形Fractal,是1975年由Mandelbrot开创的新学科。“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质。
分形是在不同尺度上都具有相似性的事物。
代码:
# 分形树: 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) # 画树干长度75的二叉树 t.hideturtle() turtle.done()
- 谢尔宾斯基Sierpinski三角形:
分形构造,平面称谢尔宾斯基三角形,立体称谢尔宾斯基金字塔。实际上,真正的谢尔宾斯基三角形是完全不可见的,其面积为0,但周长无穷,是介于一维和二维之间的分数维(约1.585维)构造。
根据自相似特性,谢尔宾斯基三角形是由3个尺寸减半的谢尔宾斯基三角形按照品字形拼叠而成。由于我们无法真正做出谢尔宾斯基三角形(degree —> ∞),只能做degree有限的近似图形。
在degree有限的情况下,degree=n的三角形,是由3个degree=n-1的三角形按照品字形拼叠而成。同时,这3个degree=n-1的三角形边长均为degree=n的三角形的一半(规模减小)。当degree=0,则就是一个等边三角形,这是递归基本结束条件
代码参考一个更好理解的代码:
#!/usr/bin/python3 import turtle t = turtle.Turtle() def get_midpoint(a, b): ax, ay = a bx, by = b return (ax + bx) / 2, (ay + by) / 2 def draw_triangle(a, b, c): ax, ay = a bx, by = b cx, cy = c t.penup() t.goto(ax, ay) t.pendown() t.goto(bx, by) t.goto(cx, cy) t.goto(ax, ay) t.penup() def draw_sierpinski(triangle, depth): """ :param triangle: 指定三角形三个顶点坐标,示例:((ax,ay),(bx,by),(cx,cy))。 :param depth: 指定层数 """ a, b, c = triangle draw_triangle(a, b, c) if depth == 0: return else: d = get_midpoint(a, b) e = get_midpoint(b, c) f = get_midpoint(c, a) draw_sierpinski([a, d, f], depth-1) draw_sierpinski([d, b, e], depth-1) draw_sierpinski([f, e, c], depth-1) if __name__ == '__main__': triangle = [[-200, -100], [0, 200], [200, -100]] draw_sierpinski(triangle, 5) turtle.done()
原课程代码为:
import turtle def sierpinski(degree,points): colormap = ['blue','red','green','white','yellow','orange'] drawTriangle(points,colormap[degree]) if degree>0: sierpinski(degree-1, {'left':points['left'], 'right':getMid(points['left'],points['right']), 'top':getMid(points['top'],points['left'])}) sierpinski(degree-1, {'left':getMid(points['top'],points['left']), 'right':getMid(points['left'],points['right']), 'top':points['top']}) sierpinski(degree - 1, {'left': getMid(points['top'], points['left']), 'right': points['right'], 'top': getMid(points['top'], points['right'])}) 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])/2,(p1[1]+p2[1])/2) t = turtle.Turtle() points = {'left':(-200,-100), 'top':(0,200), 'right':(200,-100)} sierpinski(5,points) turtle.done()
- 汉诺塔问题:
def moveTower(height,fromPole,withPole,toPole): if height>=1: moveTower(height-1,fromPole,toPole,withPole) moveDisk(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")
参考博文:
https://blog.csdn.net/python1639er/article/details/104038495?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159471622819725219913743%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=159471622819725219913743&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~pc_rank_v2-4-104038495.first_rank_ecpm_v3_pc_rank_v2&utm_term=python%E8%B0%A2%E5%B0%94%E5%AE%BE%E6%96%AF%E5%9F%BA
- 基于python的数据结构和算法(北京大学)散列表
- 基于python的数据结构和算法(北京大学)第七章(排序和查找)
- 基于python的数据结构和算法(北京大学)第六章(贪心策略和动态规划)
- python基于右递归解决八皇后问题的方法
- Python基于递归和非递归算法求两个数最大公约数、最小公倍数示例
- 基于Python数据结构之递归与回溯搜索
- python基于右递归解决八皇后问题的方法
- Python基于递归实现电话号码映射功能示例
- 基于 Python 的文件递归搜索
- MOOC —— Python语言基础与应用 by 北京大学 第五章 计算和控制流(一)
- python基于递归解决背包问题详解
- python2.7基于selenium的web自动化测试项目--contract
- 通过python获取kvm虚拟机的监控信息(基于libvirt API)
- 基于Python的opencv学习练习(七)二值化
- 基于python的kaggle练习(一)-共享单车数据分析
- python标准库 第五章 数学计算
- Python中的callable是基于什么样的机制实现的
- python实现二叉树的建立以及遍历(递归前序、中序、后序遍历,队栈前序、中序、后序、层次遍历)
- 配置maskrcnn环境基于windows 7,cpu,pycharm,anaconda3,python3.6
- 基于python的信号小波分析