文章目录

  • 一、初识递归
  • 二、进制转换
  • 三、递归可视化
  • 四、汉诺塔问题求解
  • 五、总结

一、初识递归

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

递归为我们提供了一种对复杂问题的优雅解决方案,精妙的递归算法常会出奇简单,令人赞叹。

给定一个列表,返回所有数的和,列表中数字的个数不定,需要一个循环和一个累加变量来迭代求和,那现在既不能用 for 循坏,也不能用 while 循环,我们可以用递归的方法来解决问题!

思路:

  • 数列求和问题首先具备了基本结束条件:当列表长度为 1 的时候,直接输出所包含的唯一数。
  • 数列求和处理的数据对象是一个列表,而基本结束条件是长度为 1 的列表,那递归算法就要改变列表并向长度为 1 的状态演进,代码实现时具体做法是将列表长度减少1。
  • 调用自身:实际上可以理解为"问题分解成了规模更小的相同问题",在数列求和算法中就是"更短数列的求和问题"。

递归实现数列求和如下:

def sum_n(lst):return lst[0] if len(lst) <=1 else lst[0] + sum_n(lst[1:])print(sum_n([1, 3, 5, 7, 9]))

递归算法三定律:

  • 递归算法必须要有结束条件(最小规模问题的直接解决)
  • 递归算法必须能改变状态向基本结束条件演进(减小问题规模)
  • 递归算法必须调用自身(解决减小了规模的相同问题)

递归调用的实现:

  • 当一个函数被调用的时候,系统会把调用时的现场数据压入到系统调用栈。每次调用,压入栈的现场数据称为栈帧,当函数返回时,要从调用栈的栈顶取得返回地址,恢复现场,弹出栈帧,按地址返回。
  • 在调试递归算法程序的时候经常会碰到这样的错误:RecursionError: maximum recursion depth exceeded in comparison,原因递归的层数太多,但系统调用栈容量是有限的。

爆栈是非常危险的操作,在实际开发写递归算法时应尽力避免。Python内置的 sys 模块可以获取和调整最大递归深度,操作如下:

二、进制转换

  • 十进制有十个不同符号:dec_str=“0123456789”,比 10 小的整数,转换成十进制,直接查表就可以得到:dec_str[n],把比 10 大的整数,拆成一系列比十小的整数,逐个查表,比如七百六十九,拆成七、六、九,查表就可以得到769。
  • 所以,在递归三定律里,我们找到了 “基本结束条件”,就是小于 10 的整数拆解整数的过程就是向“基本结束条件”演进的过程”。
  • 我们用整数除,和求余数两个计算来将整数一步步拆开,除以 “进制基base”(//base) 对 “进制基” 求余数(%base)

递归实现如下:

def dec_conversion_n(n, base):str_list = "0123456789ABCDEF"if n < base:return str_list[n]  # 到了最小规模  查表else:   # 减小规模  调用自身return dec_conversion_n(n // base, base) + str_list[n % base]print(dec_conversion_n(233, 8))

结果如下:


还可以写得更优雅一些:

def dec_conversion_n(n, base):str_list = "0123456789ABCDEF"return str_list[n] if n < base else dec_conversion_n(n // base, base) + str_list[n % base]print(dec_conversion_n(233, 8))

余数总小于"进制基base",整数商小于进制基时,达到递归结束条件,可直接进行查表转换,整数商成为 “更小规模” 问题,通过递归调用自身解决。

三、递归可视化

通过可视化来展现递归调用。

import turtlet = turtle.Turtle()
def draw_spiral(line_len):if line_len > 0:t.forward(line_len)t.right(90)draw_spiral(line_len - 5)draw_spiral(160)
turtle.done()


用分形树更形象地展现递归调用。分形是在不同尺度上都具有相似性的事物,分形树特征:子图结构与自身相似,很容易想到递归。

python中的 turtle 的使用,可以很方便地画出分形树,画分形树的思想也可以用到二叉树的遍历中,实现如下:

def draw_tree(branch_len):if branch_len > 5:t.forward(branch_len)t.right(20)draw_tree(branch_len - 15)t.left(40)draw_tree(branch_len - 15)t.right(20)t.backward(branch_len)print(":".join(["CSDN叶庭云", "https://yetingyun.blog.csdn.net/"]))
t = turtle.Turtle()
t.left(90)
t.penup()
t.backward(100)
t.pendown()
t.pencolor('red')
t.pensize(2)
draw_tree(75)
t.hideturtle()
turtle.done()

效果如下:


把树分解为三个部分:树干、左边的小树、右边的小树分解后,正好符合递归的定义:对自身的调用。

谢尔宾斯基三角形(英语:Sierpinski triangle)也是一种分形,由波兰数学家谢尔宾斯基在 1915 年提出,它是自相似集的例子。根据自相似特性,谢尔宾斯基三角形是由 3 个尺寸减半的谢尔宾斯基三角形按照品字形拼叠而成,由于我们无法真正做出谢尔宾斯基三角形(degree趋于无穷),只能做 degree 有限的近似图形。

在 degree 有限的情况下,degree=n的三角形,是由 3 个 degree=n-1 的三角形,按照品字形拼叠而成。同时,这 3 个 degree=n-1 的三角形边长均为degree=n的三角形的一半(规模减小)。当degree=0,则就是一个等边三角形,这是递归基本结束条件。作图如下:

# -*- coding: UTF-8 -*-
"""
@Author   :叶庭云
@公众号    :AI庭云君
@CSDN     :https://yetingyun.blog.csdn.net/
"""
import turtledef drawTriangle(points, color, my_turtle):   # 绘制等边三角形my_turtle.fillcolor(color)my_turtle.up()my_turtle.goto(points[0][0], points[0][1])my_turtle.down()my_turtle.begin_fill()my_turtle.goto(points[1][0], points[1][1])my_turtle.goto(points[2][0], points[2][1])my_turtle.goto(points[0][0], points[0][1])my_turtle.end_fill()def getMid(p1, p2):       # 取两个点的中心return (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2def sierpinski(points, degree, my_turtle):colormap = ['blue', 'red', 'green', 'white','yellow', 'violet', 'orange']drawTriangle(points, colormap[degree], my_turtle)if degree > 0:sierpinski([points[0],getMid(points[0], points[1]),getMid(points[0], points[2])],degree - 1, my_turtle)sierpinski([points[1],getMid(points[0], points[1]),getMid(points[1], points[2])],degree - 1, my_turtle)sierpinski([points[2],getMid(points[2], points[1]),getMid(points[0], points[2])],degree - 1, my_turtle)def main():print(":".join(["CSDN叶庭云", "https://yetingyun.blog.csdn.net/"]))myTurtle = turtle.Turtle()myWin = turtle.Screen()myPoints = [[-100, -50], [0, 100], [100, -50]]   # 外轮廓三个顶点sierpinski(myPoints, 4, myTurtle)   # 画degree=5的三角形myWin.exitonclick()main()

效果如下:

四、汉诺塔问题求解

问题来源:汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从上往下从小到大顺序摞着 64 片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘,只能移动在最顶端的圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。

推荐一个可以在线玩汉诺塔小游戏的网站:
http://www.htmleaf.com/Demo/201508272485.html

移 3 个盘子演示如下:


思路:

  • 将盘片塔从开始柱,经由中间柱,移动到目标柱:首先将上层N-1个盘片的盘片塔,从开始柱,经由目标柱,移动到中间柱;然后将第N个(最大的)盘片,从开始柱,移动到目标柱;
  • 最后将放置在中间柱的 N-1 个盘片的盘片塔,经由开始柱,移动到目标柱。基本结束条件,也就是最小规模问题变为:1个盘片的移动问题

Python代码递归实现如下:

def move_tower(height, start_pole, mid_pole, target_pole):if height >= 1:# 开始柱  目标柱  中间柱move_tower(height - 1, start_pole, target_pole, mid_pole)# 记录移动move_disk(height, start_pole, target_pole)# 中间柱  开始柱  目标柱move_tower(height - 1, mid_pole, start_pole, target_pole)def move_disk(disk, start_pole, target_pole):print(f"将 {disk} 号盘子从 {start_pole}号柱 移到 {target_pole}号柱")print(":".join(["CSDN叶庭云", "https://yetingyun.blog.csdn.net/"]))
move_tower(3, "1", "2", "3")    # 2^n - 1次
print("Complete!")

结果如下:


和动图里我们玩游戏的操作步骤一致!

五、总结

递归是解决某些具有自相似性的复杂问题的有效技术

递归算法三定律:

  • 递归算法必须要有结束条件(最小规模问题的直接解决)
  • 递归算法必须能改变状态向基本结束条件演进(减小问题规模)
  • 递归算法必须调用自身(解决减小了规模的相同问题)

注意:

  • 某些情况下,递归可以代替迭代循环,递归算法通常能够跟问题的表达自然契合。
  • 递归不总是最合适的算法,有时候递归算法会引发巨量的重复计算,"记忆化/函数值缓存"可以通过附加存储空间记录中间计算结果来有效减少重复计算。
  • 如果一个问题最优解包括规模更小相同问题的最优解,这时我们可以用动态规划来解决。

Python编程 深入浅出递归相关推荐

  1. python编程入门十三:递归

    第十三章:递归 说到递归,或许你也听说过递推,这两个概念其实应该算到算法的行列,在python编程入门的教程中我们也只是简单的讲一下,知道这个概念以及可以简单的应用就可以:本章其实也应该属于函数的范畴 ...

  2. Python从入门到实践电子书,python编程入门到实践pdf

    <Python编程从入门到实践>txt下载在线阅读,求百度网盘云资源 <Python编程>([美]埃里克·马瑟斯(Eric Matthes))电子书网盘下载免费在线阅读资源链接 ...

  3. 中文版开源!这或许是最经典的Python编程教材

    整理 | AI科技大本营(ID:rgznai100) 想入门Python,但一直没找到合适的参考书籍? <Think Python>是很多Python初学者的不二入门教材,受到广泛好评.该 ...

  4. 学习Python编程的19个资源

    用Python编写代码一点都不难,事实上它一直被赞誉为最容易学的编程语言.如果你准备学习web开发, Python是一个不错的开始,甚至想做游戏的话,用Python来开发游戏的资源也有很多.这是快速学 ...

  5. python入门教程非常详细-Python编程入门教程:从入门到高级,非常详细

    本文的资料和内容是我下载的,觉得非常有用,于是转过来大家瞧瞧: 这里给初学Python的朋友提供一些建议和指导吧.大神请无视, 俗话说:授人以鱼不如授人以渔.所以我这里只是阐述学习过程,并不会直接详细 ...

  6. python编程入门经典 评分-豆瓣评分爆炸!Python+机器学习经典图书

    全场自营图书每满 100 减 50 元 .满 200 元减 100 元, 另外当当还特意为[机器学习算法与Python实战]读者提供了一批可与满减叠加使用的"满 200 减 40" ...

  7. python软件是免费的吗-Python编程软件下载

    Thonny是一款Python编程工具,非常适合Python的初学者使用,简单易操作,有错误的部分会直接显示出来,对于一些难懂的部分会给予解释,非常的人性化,需要的朋友欢迎下载使用. 软件优势 初始布 ...

  8. 自学python要看哪些书籍-学习Python编程的最好的7本书

    Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 读书是汲取某个特定学科的知识以及更深入的理解该学科的最好的方式.在这个科技世界,通晓计算机系统各个不同的技 ...

  9. python北京理工大学推荐的书-2020最新的学Python编程的五本必读好书

    我从海量Python图书中精挑细选了5本Python完整技术栈相关的书籍.读书,只读好书,经典好书,这5本就是! 提前说一句,可能对大部分人来说,买实体书不现实,因为我是一名python开发工程师,所 ...

最新文章

  1. const * 和 * const 的区别
  2. ios开发之 icon规范+启动图规范+启动页规范
  3. [攻防世界 pwn]——CGfsb
  4. gdb调试器命令(zz)
  5. 优麒麟 20.04 LTS 版本发布,UKUI3.0 灵动转身
  6. RFID技术正助力物流行业进入新时代
  7. java生成base64图片条形码
  8. The working copy needs to be upgraded
  9. 福州到横店嘉兴三日游(仅供参考)
  10. 了解下STRAIGHT_JOIN
  11. 关于group by的用法
  12. AI 量化机器人,人工智能如何助你从股市发家?
  13. 清华大学新闻学考研专业课真题经验分享
  14. 集客 ap ac扫盲贴 来自恩山论坛
  15. POJO类中布尔类型属性的定义与命名
  16. ESOURCE_LOCKED - cannot obtain exclusive access to locked queue '2484_0_00163'
  17. Windows自带的录屏怎么用?Windows自带的录屏能录多久
  18. linux /etc/fstab 文件详细说明
  19. 百度收录批量查询_鸿叔教你操作百度霸屏,一个月赚5000块!(内附详细操作笔记!)...
  20. 【超详细科普贴】wifi共享精灵抢先版怎么用?

热门文章

  1. Github testerSunshine/12306 Linux系统部署
  2. 佛说:情绪,就是心魔
  3. 【博客573】linux内核层丢包排查方法汇总
  4. C# 开发DirectX.DirectSound录音在Win10兼容解决方法
  5. php react ssr,React-SSR
  6. 计算出1到1000以内所有不能被7整除的整数之和
  7. win8中vm12安装macosx10.11
  8. Unicode等各种码的汇总
  9. Spark SQL:从入门到精通(一)[SparkSQL初体验]
  10. 蚂蚁金服Java岗社招面试5面历程