Python递归函数相关

  函数中调用其他函数是解决实际问题中常用方法,递归函数便是函数在运行过程中调用自身的函数。它像是循环的另一种表达方式,不过相较于写循环,递归函数封装性较好、可读性较强。在解决一些循环问题时,使用递归函数往往更简洁有效。以往提到递归函数时,理解仅仅到它比循环更简洁。今天读了博主程序员的人生A的博客后,学习到递归函数的调用机制以及通过尾递归优化解决栈溢出的问题,特留随笔,作温习记录用。

  首先递归函数的调用是通过栈(stack)这一种数据结构实现,每多一次函数调用/返回,栈就增加/减少一层栈帧。既然提到它,不妨大致复习一下堆栈的相关。提栈就不得不提它的两个操作及一个性质:入栈(PUSH)和出栈(POP),他们按照先入后出、后入先出的顺序操作。进栈出栈就像往一个盒子里取放东西,先放的被后放的压在下面,要想取到下面的,自然要先拿出在上面的。栈之所以于程序有着至关重要的作用,是因为栈保存了一个程序调用时所需的维护信息,称为堆栈帧或活动记录。它一般包含几部分:1、函数的返回地址和参数;2、临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。堆栈的实质是一种运算受限于一端的线性表。那既然是线性表,大小自然是有限的。因此,当递归函数调用次数过大(即参数过大时),便会出现“栈溢出”的现象。

  解决“栈溢出”的方法则是“尾递归优化”。尾递归是指在函数返回的时候,调用自身且return语句中不能包含表达式。这样编译器就可以把尾递归做优化,使递归本身无论被调用多少次,都只占用一个栈帧,这样便不会出现栈溢出的情况。

用最简单的阶乘函数举例。

使用循环计算1*2*3*...*n:

n = int(input("输出一个数:"))if n == 0:    sum = 0else:    sum = 1for i in range(1,n+1):    sum *= iprint("它的阶乘为:",sum)

使用递归函数计算:
def recursion(n):    if n==1:        return 1    return n * recursion(n - 1)a = int(input("输入一个数:"))print("它的阶乘为:", recursion(a))但当a过大时,编译器便会因栈溢出而报错,这是就需要用到尾递归优化。

尾递归优化:
def recursion(n):    return fact_iter(n, 1)def fact_iter(num, product):    if num == 1:        return product    return fact_iter(num - 1, num * product)优化后,函数仅返回递归函数本身,这样栈帧中数据每一次使用后更新,栈不再增长,无论调用多少次都不会导致栈溢出。遗憾的是python解释器并没有针对尾递归做优化,因此用python时即使进行了尾递归优化,还是会导致栈溢出。

原文地址:https://www.cnblogs.com/Aquish/p/12250434.html

时间: 2024-10-10 08:49:11

Python递归函数相关的相关文章

汉诺塔问题的Python递归实现

汉诺塔问题的python递归实现 学习python遇到的第一个问题:汉诺塔问题的实现.首先是不知道什么是汉诺塔问题,然后是不知道怎么实现.于是百度了下,结果如下: 汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具.大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘.大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上.并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘 def hanoi(n,x,y,z): i

Python递归报错:RuntimeError: maximum recursion depth exceeded in comparison

Python中默认的最大递归深度是989,当尝试递归第990时便出现递归深度超限的错误: RuntimeError: maximum recursion depth exceeded in comparison 简单方法是使用阶乘重现: 1 #! /usr/bin/env Python 2 3 def factorial(n): 4 5 if n == 0 or n == 1: 6 7 return 1 8 9 else: 10 11 return(n * factorial(n - 1)) >

Python递归遍历目录下所有文件

#自定义函数: import ospath="D:\\Temp_del\\a" def gci (path): parents = os.listdir(path) for parent in parents: child = os.path.join(path,parent) #print(child) if os.path.isdir(child): gci(child) # print(child) else: print(child) gci(path) #使用os.walk方

Python递归实现汉诺塔

Python递归实现汉诺塔: def f3(n,x,y,z): if(n==1): print(x,'--->',z) else: f3(n-1,x,z,y) print(x,'--->',z) f3(n-1,y,x,z) n=int(input('请输入汉罗塔层数:')) f3(n,'X','Y','Z') 运行结果如下:

Python递归及斐波那契数列

递归函数 在函数内部,可以调用其他函数.如果一个函数在内部调用自身本身,这个函数就是递归函数.举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以看出:fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n所以,fact(n)可以表示为 n * fact(n-1),只有n=1时需要特殊处理.于是,fact(n)用递归的方式写出来就是: def fact(

Python递归中 return 代码陷阱

最近写接口测试程序中,需要查询多层嵌套字典中某个Key的值,查到则返回,查不到返回None,查询的Key可以是任意层次的Key,如 Value本身也是多层字典,或者Key已经是叶子结点. 思想:利用Python的递归思想,逐层深入遍历,最后返回结果值 最终的成品代码参考了一下博客内容: http://www.cnblogs.com/hahaweixiaohenqingcheng/archive/2016/11/14/6062961.html#undefined 尝试多次后发现参考代码已经无法再深

用python递归实现组合,以及关于递归的个人感想

上代码先: def fib(nlist,res): print_list = [] print_list.extend(res) print_list.append(nlist if not nlist else nlist[0]) if len(nlist)==1: print '#############print_list',print_list return temp_list = [] temp_list.extend(nlist) for i in range(len(temp_li

Python递归和迭代

递归 在函数内部,程序调用自身的编程技巧称为递归( recursion).递归函数结构清晰,很直观的理解计算过程,但也有严重缺点:相对于普通循环而言,递归运行效率较低,经过很多冗余的计算,递归会消耗大量的调用堆栈.在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧.每当函数返回,栈就会减一层栈帧.由于栈的大小不是无限的,因此,递归调用的次数过多,会导致栈溢出.因此,应该尽量用循环代替递归.在递归调用的过程当中系统为每一层的返回点.局部量等开辟了栈

python递归次数和堆栈溢出问题

在做递归的时候,测试了一下python的递归能力. 如果不设置递归次数的话,大概只能在992次左右,就会出现错误:RuntimeError: maximum recursion depth exceeded 如果使用代码: import sys sys.setrecursionlimit(1000000) #例如这里设置为一百万 设置了递归次数,到了9656次就会出现stack overflow的问题.查了一下,如果换成64位的python会好点.但是做递归容易引起溢出这个问题还是听蛋疼的,数据