Python数据结构14:递归的原理,递归实现数列求和、求阶乘、十进制转为任意进制

python基础算法合集(2)(递归算法)斐波那契数列 上期我们用最普通的算法写了斐波那契数列,本期我们用递归的算法写。同样的程序效果。 所谓递归就是函数自己调用自己,但首先递归需要有个出口,不然程序会 陷入死循环的。 用递归写斐波那契数列: 递归算法主要是通过列表的切片功能判断数字的索引,即本程序是通过索引的位置计算斐波那契数列的值的。 首先定义一个函数体fib(n),参数是接收由用户输入的数列的长度,如果索引是1或2,表示数列的第一个和第二个数字,那么就返回[1]、[1、1],通过这个功能将第一个和第二个数字剔除了。那么从所以2开始就是表示数列的第三个是数字 阅读详情

1. 概念:什么是递归?

递归(Recursion)是一种解决问题的方法。尤其是复杂问题,有时用递归解决复杂问题可能会出奇的简单。

递归将一个比较复杂的问题分解成更小规模的问题,持续分解直到问题规模小到可以用非常简单的方式直接解决。

分解在算法上的表现出来的就是:在算法流程中调用自身。

2. 举例说明递归:数列求和

问题:给定一个列表,返回所有数的和,列表中数的个数不定。

2.1 用循环的解法:

需要一个循环和一个累加变量来迭代求和。

def sum_list(alist):
    sum_of_list = 0
    for i in alist:
        sum_of_list = sum_of_list + i
    return sum_of_list


print(sum_list([1, 3, 5, 7, 9]))

2.2 如果不使用while或for的话,还能求解吗?

数列求和,其实是由很多次的两个数相加实现的。我们需要做的,是如何将规模大的数列求和分解为规模小的两数求和。同样属于求和问题,只是规模发生了变化,这就是递归解决问题的特征。

对[1, 3, 5, 7, 9]这个数列进行求和,除了循环,还有另外一种方式:全括号表达式(1 + (3 + (5 + (7 + 9))))
最内层的 (7 + 9) 直接相加就可以计算的出。
然后 (5 + (7 + 9)) 就可以用 (5 + 16) 直接计算出。
整个求和的过程就是:

整个问题就可以归纳成:
数列和 = “首个数” + “余下数列和”
当余下数列只有一个数时,它的“数列和”就是它本身。此时,规模就已经小到了可以直接解决。

sum_list(alist)=alist[0]+sum_list(alist[1:]) sum\_list(alist) = alist[0] + sum \_ list(alist[1: ])sum_list(alist)=alist[0]+sum_list(alist[1:])

写成代码就是:

def sum_list(alist):
    # 问题的最小规模,直接输出
    if len(alist) == 1:
        return alist[0]
    else:
        # 调用函数自身,减小函数的规模
        return alist[0] + sum_list(alist[1:])


print(sum_list([1, 3, 5, 7, 9]))

这个程序的重点在于:

  1. 给出了最小规模的条件,可以直接解决最小问题。
  2. 具备分解问题的步骤,通过调用函数自身减小问题的规模。

函数的执行和返回过程如下图。

2.3 递归三定律

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

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

2.4 简易高效理解

如果你还没懂的话,问题不大,因为我看完了也是懵的。

对于递归有没有什么好的理解方法? - 方应杭的回答 - 知乎
https://www.zhihu.com/question/31412436/answer/738989709

这篇文章能更帮助理解。

3. 递归的应用

3.1 十进制整数转换为任意进制

之前曾用栈实现过进制的转换,这里,采用递归实现。递归和栈具有一定的关系。递归要解决的是从十进制到二进制、四进制、八进制、十六进制等进制的任意进制转换。

首先来看最熟悉的十进制,即十进制整数转换为十进制。

十进制包含10个符号:conv_string = “0123456789”

对于小于10的十进制整数,如“5”,直接查表就行了
conv_string[5]
因此本题的基本结束条件就是一位的整数小于基(即进制数,十进制的基就是10,十六进制的基就是16),直接查表并输出。

对于大于10的十进制整数,如“769”,延续上面的方法,把“769”拆分成多个小于“10”的整数就行了,即拆分成 “7” , “6”, “9”,然后将这个三个小字符串拼接即可。现在问题就在于拆分的方法。

拆分的目的在于每次从多位的整数中分离出一位小于基整数,对于769,拆分的过程就是:“769” = “76” + “9” , “76” = “7” + “6” 。在分离的过程中,这个多位的整数位数朝着变成一位整数的方向发展,这就是本体的想基本结束条件演进(减小规模)

拆分可以同时使用求余数和整数除,求余数用于分离出大整数的最后一位,整数除用于保留除最后一位外的前面几位。
具体来讲,整数除是“十进制整数 // 基base”。
求余数“十进制整数 % 基base”。

例如:
769 % 10 = 9 < 10 -> “9”
769 // 10 = 76

76 % 10 = 6 < 10 -> “6”
76 // 10 = 7 < 10 -> “7”

整数就是 “7” + “6” + “9” = “769”

基本结束条件就是余数小于10。
减小规模就是整数除后的商位数小于原整数。
调用自身就是每次对整数商使用自身函数减少规模。

流程图如下:

类比到十进制转为二进制,十进制转为十六进制也是一样的。
769 // 2 = 384
769 % 2 = 1 < 2 -> 1
384 // 2 = 192
384 % 2 = 0 < 2 -> 0
192 // 2 = 96
192 % 2 = 0 < 2 -> 0
96 // 2 = 48
96 % 2 = 0 < 2 -> 0
48 // 2 = 24
48 % 2 = 0 < 2 -> 0
24 // 2 = 12
24 % 2 = 0 < 2 -> 0
12 // 2 = 6
12 % 2 = 0 < 2 -> 0
6 // 2 = 3
6 % 2 = 0 < 2 -> 0
3 // 2 = 1 < 2 -> 1
3 % 2 = 1 < 2 -> 1
从下往上把字符串拼接起来
所以 769 转成 二进制 就是 1100000001

代码如下:

def to_str(number, base):
    convert_str = "0123456789ABCDEF"
    if number < base: # 最小结束条件
        return convert_str[number]
    else:
        return to_str(number // base, base) + convert_str[number % base]  # 向最小结束条件演化


print(to_str(769, 2))
print(to_str(769, 10))
print(to_str(769, 16))

3.2 求阶乘

直接给出代码吧。

def fac(n):
    if n != 1:
        result = n * fac(n - 1)  # 向基本结束条件 n = 1 演进
    else:  # 基本结束条件,当1的阶乘等于1
        result = 1
    return result


print(fac(6))

4. 递归

调用在系统中是怎么实现的

4.1 递归实现的原理

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

意思是最外层的第一次调用被压入栈底,当他前面的那些操作(即里层的自身函数)都弄完了,才轮到它。而最内层的符合最小结束条件的是第一个解决并将结果返回的,以保证后面的操作可以顺利执行。

4.2 Python中的递归深度限制

在调用递归算法的程序时,会遇到这样的错误:RecursionError。如下图。

这是因为递归的层数太多,而系统调用栈容量有限。

解决方法:
要检查程序中是否忘记设置基本结束条件,导致无限递归。
或者向基本结束条件演进太慢,导致递归层数太多,调用栈溢出。

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

递归的影视作品:
前目的地
恐怖游轮

参考文献

本文的知识来源于B站视频 【慕课+课堂实录】数据结构与算法Python版-北京大学-陈斌-字幕校对-【完结!】,是对陈斌老师课程的复习总结

利用递归求给定数组的和 求数组的和并返回结果,利用循环简直分分钟就能完成这个任务 给定一个数组,例如2,4,5,6,7。 求和简直不要太容易,过程不用说,直接累加就好,代码在下面: #include&lt;stdio.h&gt; #include&lt;iostream&gt; using namespace std; int sum(int a[],int n){ int res=0; for(int... 阅读详情

相关推荐

进制转换 把一个任意的十进制正整数 N 转换成 d 进制数。 N 是一个正整数,d 是一个大于 1 小于 10 的整数,二者均由用户输入,且两数字用换行分隔。

进制转换 把一个任意的十进制正整数 N 转换成 d 进制数。 N 是一个正整数,d 是一个大于 1 小于 10 的整数,二者均由用户输入,且两数字用换行分隔。

方法递归:计算1~100的和

public class Recursion{ public static void main(String[] args){ System.out.println(sum(100)); } public static int sum(int num){ if(num == 1){ return 1; } return num + sum(num-1); } }

优快云_meishouquan的博客 4407

使用GitLab+Drone CI持续集成自动部署web项目,图文详细

kind: pipeline # 定义对象类型,还有secret和signature两种类型 type: docker # 定义流水线类型,还有kubernetes、exec、ssh等类型 name: mall-tiny-drone # 定义流水线名称 steps: # 定义流水线执行步骤,这些步骤将顺序执行 - name: package # 流水线名称 image: maven:3-jdk-8 # 定义创建容器的Docker镜像 volumes: # 将容器内目录挂载到宿主机,仓库

4105

递归累加求和

递归累加求和 计算1 ~ n的和 分析:num的累和 = num + (num-1)的累和,所以可以把累和的操作定义成一个方法,递归调用 实现代码: public class DiGuiDemo { public static void main(String[] args) { //计算1~num的和,使用递归完成 int num = 5; // 调用求和的方法 int sum = getSum(num); // 输出结果 System.out.println(sum);

super_Fake的博客 4137

达梦数据库连接报错6001网络通信异常

本文主要记录客户端连接达梦数据库报错6001网络通信异常问题分析过程、问题原因以及问题解决方法。

chen_zizi2025的博客 2769

升级最新IDEA版本(2022.1.1)

升级最新IDEA版本(2022.1.1)

软件老王 3万+

递归求和

用递归的方式进行求和 1:什么是递归 在计算机编程里,递归指的是一个过程:函数不断引用自身,直到引用的对象已知。通俗一点的说,递归就是一个在执行一个函数时,函数内部自我调用的过程。 写一个简单的递归求和的函数。   function   getSum(n){     if(n<1){       return 0;     }     return n+getSum...

diechuan9289的博客 577

解决TexStudio编写LaTeX论文引用文献问题:正文引用处出现[?],参考文献也不显现

当我们利用LaTeX编写论文时,可能会出现引用参考文献时正文引用处出现?号,肯能的原因及解决方案如下: 问题一 忘记在\end{document}前面放\bibliographystyle{样式}和\bibliography{参考文献bib文件名}: \bibliographystyle{plain} \bibliography{sample} 其中, LaTeX 标准选项及其样式共有以下8种: plain,按字母的顺序排列,比较次序为作者、年度和标题. unsrt,样式同plain,只是按照引用的先后

左手の明天的博客 9529

Python递归思想与代码实现

1, 递归思想 递归算法:递归(Recursion),在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。 这是官方的解释,翻译成人话就是: 函数内部自己调用自己 函数必须有出口 函数自己调用自己很好理解,但什么是出口呢?我们知道,递归实际上是简化嵌套for循环的一种精简算法,所以在函数内部自己调用自己的过程就是在不短的循环,并改变函数传入的参数。如果没有不再执行自己调用自己的出口,那么递归就会陷入无限循环的无底洞。 出口通常是用return或if else语句bi mian ...

nouniuniu的博客 1916

YOLOv11改进有效系列目录 - 包含卷积、主干、检测头、注意力机制、Neck上百种创新机制 - 针对多尺度、小目标、遮挡、恶劣天气等问题

在一些特定情况下,目标检测任务由于多种因素的影响,变得更加复杂和困难。以下是几类常见的困难目标检测场景:1. 小目标检测定义:小目标检测是指当目标在图像中的占比非常小时,模型需要准确识别和定位这些目标。典型场景包括远程监控、卫星图像分析等。挑战1. 低分辨率:由于目标在图像中占据像素较少,细节缺失,特征提取难度增加。2. 特征不足:小目标缺乏明显的形状和纹理特征,容易被复杂背景淹没。3. 检测难度大:由于小目标与背景之间的对比度较低,误检的几率上升。4. 数据不平衡。

qq_64693987的博客 4万+

Microsemi Libero系列教程(四)——PLL的使用

文章目录PLL是什么Libero中PLL的使用官方文档 系列教程:Microsemi Libero系列教程 PLL是什么 PLL(Phase Locked Loop): 为锁相回路或锁相环,用来统一整合时钟信号,使高频器件正常工作,如内存的存取资料等。PLL用于振荡器中的反馈技术。 许多电子设备要正常工作,通常需要外部的输入信号与内部的振荡信号同步。一般的晶振由于工艺与成本原因,做不到很高的频率...

whik1194的博客 7212

递归问题:斐波那契数列的python代码实现

斐波那契数列(Fibonacci sequence),又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21 这是一个简单的递归调用的问题 其python的代码实现如下: def fib(n):#定义函数 if n == 1 or n == 2 :#条件判断,当数列的下标为1或2时,返回1 return 1 elif n == 0 :#要注意还有下标为0的情况 return 0 else: return fib(n

CXYCMY的博客 1455

51单片机+DS18B20+数码管显示+超温提示+Proteus仿真

51单片机+DS18B20+数码管显示+超温提示+Proteus仿真 Proteus仿真 实例代码 #include <reg52.h> #define uchar unsigned char #define uint unsigned int sbit we1 = P3^0; sbit we2 = P3^1; sbit we3 = P3^2; sbit we4 = P3^3; sbit DS = P1^0; sbit D1 = P3^6; sbit D2 = P3^7; uch

perseverance51博客 1540

递归求数组的和(数组)

递归是一种将问题分解为更小的子问题来解决的编程技巧。使用递归求数组的和是一种直观且简洁的方法。以下是详细的算法实现,包括原理、步骤、图示法表示步骤、代码关键行注释和修正后的完整代码。递归是一种简洁的方法来求解数组的和,适用于各种大小的数组。尽管递归实现简单,但在处理非常大的数组时,可能会遇到栈溢出的问题。对于大规模数据,推荐使用迭代方法。递归求数组和的核心思想是将数组分解为更小的子数组,逐步累加每个元素,最终得到总和。3. 图示法表示步骤。步骤 2:累加与返回。4. 代码关键行注释。

m0_49844997的博客 671

lammps教程:聚合物压缩,避免“bond atoms missing”

如果使用ms建模,聚合物的链会伸出到盒子外面,在导出data文件后,盒子外面的原子被周期性算法折叠进盒子对面,这就造成了边界附近的bond原子可能被分布到了盒子的两侧。并且,这个data文件不能使用npt系综进行压缩,npt系综必须使用周期性边界,在压缩时,bond原子同样会移动到对面的边界。所以,最好的解决办法是使用一个反射墙墙进行压缩,设置一个反射墙墙既可以实现压缩效果,也可以组织原子跨越box边界移动到对面。解决这个问题的原则只有一个:导出data时确保所有的bond原子没有跨越边界。

lammps_jiayou的博客 3819

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

python中用递归求和

递归函数: 直接或者间接调用自身以进行循环的函数。 这里是用递归函数编写的一个定制求和函数的列子: def mysum(l): print(l) if not l: return 0 else: return l[0] + mysum(l[1:]) print(mysum([1, 2, 3, 4, 5])) result: [1...

weixin_41407477的博客 1万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

递归算法及经典递归例子代码实现

作者:ikownyou  来源:优快云  原文:https://blog.youkuaiyun.com/ikownyou/article/details/65633581  版权声明:本文为博主原创文章,转载请附上博文链接! 一、什么叫做递归? 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法; 递归函数就是直接或间接调用自身的函数,也就是自身调用自己; 二、一般什么时候使用递归?  ...

hello world! 2万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

用Python轻松实现斐波那契数列——递归函数详解!

通过本篇文章,我们学习了Python递归函数的基本概念和实现方法,同时也掌握了斐波那契数列的常规和优化算法。如果你对于递归算法的理解更深了,那么对于其他匹配问题、遍历问题及分治问题,都将更加得心应手。

canshanyin的博客 1万+

python递归函数详解

等等都是一类递归函数,但是我们知道,它们在实现过程中需要执行多次,并且执行完第一次之后就不能再执行第二次了。也就是说,当我们在调用完递归函数之后(这里就不需要调用B了),C还会再执行一遍递归函数A。然后,我们再把一个递归函数套入到另一个程序中,这样,我们就可以在另外一个程序中直接调用这个递归函数了。当然,对于递归函数来说,最重要的一点是,在调用了递归函数之后,我们应该把函数的参数传递给另一个函数。我们可以看到,这是一个循环,而我们在第一次执行的时候,都是需要调用 printf ()函数的。

花生日记 4646

递归函数求和

递归 1.递归方式获取0-10数字之和: // 递归函数求和 var ar = [0,1,2,3,4,5,6,7,8,9]; function recursionCount(ar) { // 递归求和方式 let i = 0; function ordinary(n) { // 这个是递归函数 console.log(n) if (n >= ar.length -1 ) { // 递归结束条件 return; } i += ar[n]; // 执行逻辑 ordinary(n + 1) // 自

Xu_Chen1的博客 2945

递归(汉诺塔和递归求和)

程序调用自身的编程技巧称为递归( recursion)。递归作为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。 1.递归求和: 全代

m0_61629480的博客 788

每天一道算法题:递归求数组和的不同思路

1、递归与循环 针对刚开始接触的朋友,这里先对递归做一个简单的介绍,递归就是一个类似循环的思维,使用递归去解决问题主要是要做到构造相似性,那么怎么做到呢?主要有以下三点: 如果没有明显的相似性,需要主动构造 不能相似的原因很可能是缺少参数 递归与数学上的递推公式很类似 2、递归的思维过程 分析:举个例子,这就像平时生活中需要办理什么材料证明一样,你去找相关部门,然后他说,你还没办xxx证明,然后让你去先办xxx证明,而受理xxx证明的部门又说,你还没办xxx证明,就像踢皮球一样,他踢给她,她又踢给它,当

黑虎阿福的博客 1305

递归算法经典实例python-Python递归算法详解

递归的概念很简单,如果函数包含了对其自身的调用,该函数就是递归的。递归(Recursion),在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。在使用递归时,需要注意以下几点:递归就是在过程或函数里调用自身必须有一个明确的递归结束条件,称为递归出口。注意: 切勿忘记递归出口,避免函数无限调用。递归基本步骤每一个递归程序都遵循相同的基本步骤:1.初始化算法。递归程序通常需要一个开始时使用的...

weixin_37988176的博客 2229

递归:链表求和/反转字符串

每一对儿的节点处理都是一样的,并且不断的向后遍历,因此看到这个问题的时候可以用循环也可以用递归。有一点不同的是,子问题的入参需要预先处理,即。还有一点非常有意思,一般情况下,一个链表遍历到None的时候,就直接返回了,例如。拼接起来即可,但是这里却是不断的补充0元素,这样就可以把两个链表虚拟成一样长了。通常面对递归,我都会先思考子问题,然后根据子问题去求解原问题,这道题有两点不同。要短,因此肯定是先遍历完。,通常情况下只需要把。...

he_wen_jie的博客 772

递归进行进制转换

递归进行进制转换

CX_YX_0的博客 2347
上一篇: Python数据结构13:散列(哈希)表,完美散列函数,解决冲突方法,开放寻址,负载因子,平均查找次数
下一篇: Python数据结构15:turtle模块制图,画直线,正方形,星星,递归可视化:分形树,谢尔宾斯基三角形
YangStudent
博客等级 码龄7年 21粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值