递归与非递归 python

面试题中很多都涉及到递归与非递归,比如二分法,冒泡,归并,快排,二叉树前中后遍历等等,建议能直接给出非递归形式,如果面试官想要看到递归形式也能熟练的写出来。

典型的面试题比如说:汉诺塔问题,斐波那契数列等

递归是什么?和循环的区别

答:

递归从字面意思理解是自己调用自己,实际上递归是将问题逐渐分解减小,但是和原问题有着相同解法的问题,并且存在一个问题的出口。

循环就是重复执行同一段代码

打一个比方吧,从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚对小和尚说,从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚对小和尚说,从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚对小和尚说...... 这就是递归,循环就是 从前有座山,山里有座庙,庙里有个老和尚和小和尚。从前有座山,山里有座庙,庙里有个老和尚和小和尚。从前有座山,山里有座庙,庙里有个老和尚和小和尚。从前有座山,山里有座庙,庙里有个老和尚和小和尚。从前有座山,山里有座庙,庙里有个老和尚和小和尚。

循环和递归存在相似性但是存在本质的不同,比如都是重复操作,但是循环是一次正向的过程,递归却需要回溯。

理论上所有的递归都可以变成非递归形式,比如使用栈和循环。但是循环却不能改成递归

尾递归优化:

一些语言在编译或者解释的时候能够自动对尾递归形式进行优化,但是python并不能,所以在python中将递归改成尾递归形式仍然不能改变递归的效率差和爆栈的问题。

针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的编程语言只能通过尾递归实现循环。

递归效率低的原因:

递归的简单理解:

递归就是自己调用自己,

递归的总结:

  • 找到递归出口(终止递归的条件)
  • 找出递归表达式(规律)

下面这个就是用递归的方式计算阶乘

首先是递归的出口 n = 1

递归表达式 fact(n) = n * fact(n-1)

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

递归的缺点:

递归的缺点有两个,首先是时间效率低,需要一个展开和回溯的过程,改成循环的方式就可以避免展开的过程,其次是用栈的问题,python的递归深度最大是1000,win10系统是2MB大小,(使用ulimit -a命令查看大小限制),受限于这两种限制,使用递归就容易出现爆栈的问题。

递归改非递归:

使用栈来模拟递归展开和回溯的过程,可以避免爆栈的问题

在支持尾递归优化的语言中可以将递归改成尾递归的形式

漫谈递归转非递归 - 猿大白 - 博客园本文首发于我的公众号 Linux云计算网络(id: cloud_dev) ,专注于干货分享,号内有 10T 书籍和视频资源,后台回复 「1024」 即可领取,欢迎大家关注,二维码文末可以扫。 一:递归https://www.cnblogs.com/bakari/p/5349383.html

 递归对应的一些常见算法题

题1:计算n的阶乘

首先分析n的阶乘的一般形式是 f(n) = 1*2*.....*n

从中可以得到

f(1) = 1              递归的出口

f(n) = n * f(n-1)  递归的规律表达式

由此就可以得出递归的解法

def func(num):
    if num == 1:
        return 1
    else:
        return num * func(num-1)

python语言的话因为没有尾递归优化,所以不用考虑通过优化成尾递归的形式避免栈溢出,不过可以通过这个了解下尾递归的事情

首先尾递归是有严格规定的,不是说递归函数最后一行调用自己的函数就一定是尾递归,比如这个函数最后虽然调用了自己,但是它不是尾递归,尾递归要求在最后return自己时不能有表达式,是直接return自己

所以以上的函数为了改成尾递归的形式,可以这样调整

def func(num,temp):
    if num == 1:
        return temp
    else:
        return func(num-1,temp * num)

以上的函数是一种尾递归优化,每次调用的时候,实际上已经将阶乘的值传递给了下一个值

这个函数的展开就没有回溯的过程。但是python仍有栈溢出的问题,所以python中改成尾递归不如将递归直接改成非递归的形式。

当然这道题也有非递归的解法,直接改成循环的形式即可:

def func(num):
    temp = 1
    while(num):
        temp = temp * num
        num = num - 1
    return temp

也可以强行套公式去转换成非递归形式,类似这样,用栈去记录每一次本来需要递归中栈记录得参数:

def func(num):
    stack = list()
    while(num):
        stack.append(num)
        num = num - 1
    temp = 1
    while(stack):
        temp = stack.pop() * temp
    return temp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值