数据结构与算法python版本之线性结构之递归Recursion

  1. 递归是一种解决问题的方法,其精髓在于:将问题分解为规模更小的相同问题,持续分解,直到问题规模小到可以用非常简单直接的方式来解决;递归的问题分解方式非常独特,其算法方面的明显特征是:在算法流程中调用自身
  2. 递归为我们提供了一种对复杂问题的优雅解决方案,精妙的递归算法会出奇简单,令人惊叹

初识递归

问题:给定一个列表,返回所有数的和,列表中的个数不定,需要一个循环和一个累加变量来迭代求和
程序很简单,for循环或者while循环即可实现,但是假如没有这两种循环呢?
我们认识到求和实际上最终是由一次次的加法实现的,而加法恰有两个操作数,这个是确定的
我们看看怎么想办法,将问题规模较大的列表求和,分解为规模较小而且固定的2个数求和

接下来我们换个方式来表达数列求和,全括号表达式
(1+(3+(5+(7+9))))
上面这个例子,最内层的括号是(7+9),这是无需循环即可计算的,实际上整个求和的过程就是按照括号内一步一步计算的

因此,我们可以把上述过程中所包含的重复模式可以归纳为这样
数列的和= “首个数”+“余下数列”的和
如果数列包含的数少到只有一个的话,它的和就是这个数了,这是规模小到可以做最简单的处理

我们简单用python代码实现如下:

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、问题分解为更小规模的相同问题,并表现为”调用自身“  2、对”最小规模“问题的解决:简单直接
"""

递归”三定律“

为了向阿西莫夫的”机器人三定律“致敬,递归算法也总结出”三定律“

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

递归“三定律”:数列求和问题

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

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

整数转换为任意进制

  1. 这个在数据结构栈里面讨论过的算法又回来了,递归和栈,一定有关联
  2. 如果上次你被入栈,出栈搞的晕头转向的话,这次递归算法一定让你感到清新

我们用最熟悉的十进制分析下这个问题
十进制有十个不同符号:convString =“0123456789”
比十小的整数,转换成十进制,直接查表就可以了:convString[n]
想办法把比十大的整数,拆成一系列比十小的整数,逐个查表
比如七百六十九,拆成七、六、九,查表得到769就可以了

所以,在递归三定律里,我们找到了“基本结束条件”,就是小于十的整数,拆解整数的过程就是向“基本结束条件”演进的过程
我们用整数除,和求余数两个计算来将整数一步步拆开
除以“进制基base”(// base)
对“进制基”求余数(% base)

那么
问题就分解为:
余数总小于“进制基base”,是“基本结束条件”,可直接进行查表转换
整数商成为“更小规模”问题,通过递归调用自身解决

so
递归代码如下:

def toStr(n, base):convString ="0123456789ABCDEF"if n < base:#返回最小规模return convString[n]else:#减小规模调用自身return toStr(n//base, base) + convString[n%base]print(toStr(1456, 16))

递归调用的实现

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

Python中的递归深度限制

在调试递归算法程序的时候经常会碰到这样的错误:RecursionError
递归的层数太多,系统调用栈容量有限

这个时候要检查程序中是否忘记设置基本结束条件,导致无线递归;或者向基本结束条件演进太慢,导致递归层数太多,调用栈溢出。
比如说这样:


def tell_story():print("从前有座山,山上有座庙,庙里有个老和尚,他在讲:")tell_story()
print("给你讲个故事")
tell_story()

实际执行后的结果如下:

在这里插入图片描述

在python中,内置的sys模块可以获取和调整最大递归深度

import sysprint(sys.getrecursionlimit())sys.setrecursionlimit(3000)
print(sys.getrecursionlimit())

执行通过后:

在这里插入图片描述

递归的可视化

前面所说的种种递归算法展现了其简单而又强大的一面,但还是难有个只管的概念
下面我们通过递归作图来展示递归调用的视觉影像

递归可视化:图示

Python的海归作图系统turtle module
python内置,随时可用,以LOGO语言的创意为基础
其意向为模拟海归在沙滩上爬行而留下足迹
爬行:forward(n), backward(n)
转向:left(n), right(n)
抬笔放笔:penup();pendown()
笔属性:pensize(s); pencolor©

我们先简单做个图,代码如下:

import turtle
t = turtle.Turtle()
#作图开始
for i in range(4):t.forward(100) #指挥海归作图t.right(90)
#作图结束
turtle.done()

运行之后的结果是:
在这里插入图片描述
我们再来一个例子:螺旋

import turtle
t = turtle.Turtle()
#作图开始
def drawSpiral(t, lineLen):#不符合最小规模,直接退出if lineLen > 0:t.forward(lineLen)  # 指挥海归作图t.right(90)#减少规模,边长减去5drawSpiral(t, lineLen - 5)
drawSpiral(t, 300)#作图结束
turtle.done()

执行之后的结果是
在这里插入图片描述

分形树:自相似递归图形

分形Fractal,是1975年由Mandelbrot开创的新学科——一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似的)是整体缩小后的形状,即具有自相似的性质

自然界中能找出中所具有分形性质的物体,例如:海岸线、山脉、闪电、云朵、雪花或者树等等

自然界中所具备的分形特性,使得计算机可以通过分形算法生成非常逼真的自然场景

分形是在不同尺度上都具有相似性的实物,我们能看出一棵树的每个分叉和每条树枝,实际上都具有整棵树的外形特征(也是逐步分叉的)
这样,我们可以把树分解为三个部分:树干、左边的小树、右边的小树,分解后,正好符合递归的定义:对自身的调用;

所以我们简单来实现一个分形树的代码:

import turtledef tree(branch_len):if branch_len > 5:#树干太短不画,约束条件t.forward(branch_len)  #画树干t.right(20)     #右倾斜20度tree(branch_len - 15)   #递归调用,画右边的小树,树干减15t.left(40)    #向左回40度,即左倾斜20度tree(branch_len - 15)   #递归调用,画左边的小树,树干减15t.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(100)    #画树干长度100的二叉树
t.hideturtle()#作图结束
turtle.done()

执行完成之后的结果是
在这里插入图片描述

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

分形构造,平面称谢尔宾斯基三角形,立体称谢尔宾斯基金字塔。实际上,真正的谢尔宾斯基三角形是完全不可见的,其面积为0,但周长无穷,是介于一维和二维之间的分数维(约1.585)构造

谢尔宾斯基三角形:作图思路

根据自身相似特性,谢尔宾斯基三角形是由3个尺寸减半的谢尔宾斯基三角形按照品字形拼叠而成,由于我们无法真正做出谢尔宾斯基三角形,只能做degree有限的近似图形

在degree有限的情况下,degree=n的三角形,是由3个degree=n-1的三角形按照品字形拼叠而成

同时,这3个degree=n-1的三角形边长均为degree=n的三角形的一半(规模减小)
当degree=0,则就是一个等边三角形,这是递归基本结束条件
那我们先简单实现

import turtledef sierpinski(degree, points):colormap = ['blue', 'red', 'green', 'white', 'yellow', 'orange']drawTriangle(points, colormap[degree])if degree > 0: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']})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()

执行之后的结果是
在这里插入图片描述

分治策略与递归

分治策略
解决问题的典型策略:分而治之;将问题分为若干更小规模的部分,通过解决每一个小规模部分问题,并将结果汇总得到原问题的解
递归算法与分支策略
递归三定律:

  • 基本结束条件,解决最小规模问题
  • 缩小规模,向基本结束条件演进
  • 调用自身来解决已缩小规模的相同问题

体现了分治策略

  • 问题解决依赖于若干缩小了规模的问题
  • 汇总得到原问题的解

应用相当广泛

  • 排序、查找、遍历、求值等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/599775.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小核引导RTOS---RISC-V C906

文章目录 参考日志编译框架目标fip 启动流程fip文件组成BL2程序 总结思考备注 参考 参考1. How does FSBL load the FreeRTOS on the small core and execute it?参考2. Duo now supports big and little cores?Come and play!Milk-V Duo, start&#xff01;参考3. 使用uboo…

SQLite 4.9的虚拟表机制(十四)

返回&#xff1a;SQLite—系列文章目录 上一篇:SQLite 4.9的 OS 接口或“VFS”&#xff08;十三&#xff09; 下一篇&#xff1a;SQLite—系列文章目录 1. 引言 虚拟表是向打开的 SQLite 数据库连接注册的对象。从SQL语句的角度来看&#xff0c; 虚拟表对象与任何其他…

C++:红黑树封装实现map、set

一、map、set的底层结构 前面对map、set等树形结构的关联式容器进行了简单的介绍&#xff0c;了解到map、set都是由红黑树封装实现的。红黑树是一种由二叉搜索树进行平衡处理后的平衡树&#xff0c;其查找、插入、删除等操作的时间复杂度为O(logn)&#xff0c;详情请参考数据结…

nature| 肠道中藏着癌症免疫治疗的关键

在疾病发生过程中&#xff0c;人体共生菌发生了系统性的变化&#xff0c;起到了正向或负向作用&#xff0c;因此可以把共生菌看作人体活动的一个重要外部器官。 癌细胞通过释放特定信号&#xff0c;给免疫系统“踩刹车”&#xff0c;抑制免疫系统的识别和杀伤。这类免疫系统的…

【管理咨询宝藏49】AA银行上市发展提升分析报告

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏49】AA银行上市发展提升分析报告 【格式】PPT版本&#xff0c;可编辑 【关键词】战略规划、商业分析、管理咨询 【强烈推荐】这是一套市面上非常…

python 05文件的读写

import os f open("data/test.txt","w") #如果文件不存在就创建文件 f.write("11,12\n21,22\n") #写入两行 第一行是11&#xff0c;12 第二行 21&#xff0c;22 f.close() #打开文件后要关闭写入f open("data/test.txt","r…

vscode 安装vim插件配置ctrl + c/v功能

搜索Vim插件 插件介绍部分有提示操作 首先安装该插件&#xff0c;然后按照下述步骤设置ctrl相关的快捷键&#xff0c;以便于脱离im快捷键而愉快的敲代码。 1.在“设置”搜索框内搜索vim.handleKeys&#xff0c;选择 Edit in settings.json 2. 设置ctrl-c,ctrl-v等快捷键置为fa…

数据库系统概论(超详解!!!)第三节 关系数据库标准语言SQL(Ⅵ)

1.空值的处理 空值就是“不知道”或“不存在”或“无意义”的值。 一般有以下几种情况&#xff1a; 该属性应该有一个值&#xff0c;但目前不知道它的具体值 &#xff1b;该属性不应该有值 &#xff1b;由于某种原因不便于填写。 1.空值的产生 空值是一个很特殊的值&#x…

uniapp使用npm命令引入font-awesome图标库最新版本并解决APP和小程序不显示图标的问题

uniapp使用npm命令引入font-awesome图标库最新版本 图标库网址&#xff1a;https://fontawesome.com/search?qtools&or 命令行&#xff1a; 引入 npm i fortawesome/fontawesome-free 查看版本 npm list fortawesome在main.js文件中&#xff1a; import fortawesome/fo…

2024新版PHP在线客服系统多商户AI智能在线客服系统源码机器人自动回复即时通讯聊天系统源码PC+H5

搭建环境&#xff1a; 服务器 CPU 2核心 ↑ 运存 2G ↑ 宽带 5M ↑ 服务器操作系统 Linux Centos7.6-7.9 ↑ 运行环境&#xff1a; 宝塔面板 Nginx1.18- 1.22 PHP 7.1-7.3 MYSQL 5.6 -5.7 朵米客服系统是一款全功能的客户服务解决方案&#xff0c;提供多渠道支持…

《从零开始学架构》读书笔记(一)

目录 软件架构设计产生的历史背景 软件架构设计的目的 系统复杂度来源 追求高性能 一、单机高性能 二、集群的高性能 追求高可用 一、计算高可用 二、存储高可用 追求可扩展性 一、预测变化 二、应对变化 追求安全、低成本、规模 一、安全 二、低成本 三、规模…

Golang | Leetcode Golang题解之第16题最接近的三数之和

题目&#xff1a; 题解&#xff1a; func threeSumClosest(nums []int, target int) int {sort.Ints(nums)var (n len(nums)best math.MaxInt32)// 根据差值的绝对值来更新答案update : func(cur int) {if abs(cur - target) < abs(best - target) {best cur}}// 枚举 a…