递归函数在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函
数。(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
递归一般用于解决三类问题:
(1)数据的定义是按递归定义的。(n的阶乘)
(2)问题解法按递归实现。(回溯)
(3)数据的结构形式是按递归定义的。(二叉树的遍历,图的搜索)
递归的缺点:
递归解题相对常用的算法如普通循环等,运行效率较低。因此,应该尽量避免使用递归,除非没有更好的算法或者某种特定情况,递归更为适合的时候。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。
#递归函数 act(n) = n! = 1 x 2 x 3 x ... x (n-1) x n = (n-1)! x n = fact(n-1) x ndef fact(n):if n==1:return 1return n*fact(n-1)
尾递归是指,在函数返回的时候,调用自身本身,并且,return 语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
上面的fact(n)函数由于return n * fact(n ‐ 1)引入了乘法表达式,所以就不是尾递归了。要改成尾递归方式,需要多一点代码,主要是要把每一步的乘积传入到递归函数中:
#定义尾递归函数def fact(n):return fact_iter(n,1)def fact_iter(num,product):if num ==1:return productreturn fact_iter(num-1,num*product)#测试print fact_iter(5,1)120可以看到,return fact_iter(num ‐ 1, num * product)仅返回递归函数本身,num ‐ 1 和num * product 在函数调用前就会被计算,不影响函数调用。fact(5)对应的fact_iter(5, 1)的调用如下: '''#实现过程解读===> fact_iter(5, 1)===> fact_iter(4, 5)===> fact_iter(3, 20)===> fact_iter(2, 60)===> fact_iter(1, 120)===> 120
'''
尾递归调用时,如果做了优化,栈不会增长,因此,无论多少次调用也不会导致栈溢出。遗憾的是,大多数编程语言没有针对尾递归做优化,Python 解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。
小结
使用递归函数的优点是逻辑简单清晰,缺点是过深的调用会导致栈溢出。
针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循
环语句的编程语言只能通过尾递归实现循环。
共同学习,写下你的评论
评论加载中...
作者其他优质文章