递归和迭代

利用迭代算法处理问题,需要做好以下三个方面的工做:


  一、确定迭代变量。在能够用迭代算法处理的问题中,至少具有一个间接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。
  二、建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是处理迭代问题的关键,通常能够使用递推或倒推的方法来完成。
  三、对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,能够计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,能够建立一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。

程序调用本身的编程技巧称为递归( recursion)。 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。递归算法的执行过程分递推和回归两个阶段。在递推阶段,把较复杂的问题(规模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解。在递推阶段,必须要有终止递归的情况。在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解。

采用递归算法需要的前提条件是,当且仅当一个存在预期的收敛时,才可采用递归算法,否则,就不能使用递归算法。 迭代虽然效率高,运行时间只因循环次数增加而增加,没什么额外开销,空间上也没有什么增加,但缺点就是不容易理解,编写复杂问题时困难。

经常的看到“递归算法”、“非递归算法”,这种提法没有语义上的问题,并且我自己也这样用——递归的算法。但这也正说明了,递归不是算法,他是一种思想,正是因为某个算法的指导思想是递归的,所以才被称为递归算法;而一个有递归算法的问题,当你不使用递归作为指导思想,这样得到的算法就是非递归算法。——而对于循环能处理的问题,都有递归解法,在这个意义上说,循环算法都可以称为非递归算法。

一些经典的递归问题:
[P1] 一个饲养场引进一只刚出生的新品种兔子,这种兔子从出生的下一个月开始,每月新生一只兔子,新生的兔子也如此繁殖。如果所有的兔子都不死去,问到第 12 个月时,该饲养场共有兔子多少只?
[P2] 阿米巴用简单分裂的方式繁殖,它每分裂一次要用 3 分钟。将若干个阿米巴放在一个盛满营养参液的容器内, 45 分钟后容器内充满了阿米巴。已知容器最多可以装阿米巴 2 20 个。试问,开始的时候往容器内放了多少个阿米巴?
[P3] 日本数学家谷角静夫在研究自然数时发现了一个奇怪现象:对于任意一个自然数 n ,若 n 为偶数,则将其除以 2 ;若 n 为奇数,则将其乘以 3 ,然后再加 1 。如此经过有限次运算后,总可以得到自然数 1 。人们把谷角静夫的这一发现叫做“谷角猜想”。

迭代(iterative)和递归(recursive)可以相互转化。常常要求把递归转化为迭代。因为递归得耗费大量时间。递归的使用可以使代码更简洁清晰,可读性更好(对于初学者到不见得),但由于递归需要系统堆栈,所以空间消耗要比非递归代码要大很多,而且,如果递归深度太大,可能系统资源会不够用。在理论上,递归和迭代在时间复杂度方面是等价的(在不考虑函数调用开销和函数调用产生的堆栈开销),但实际上递归确实效率比迭代低。从算法结构来说,递归声明的结构并不总能够转换为迭代结构。从实际上说,所有的迭代可以转换为递归,但递归不一定可以转换为迭代。比如著名的Ackmann函数。任何的一种语言里面都有循环结构,但不是任何的语言都支持递归。

非递归化就是指不引入堆栈等辅助空间进行计算的算法。更确切地说,非递归是指辅助的空间为O(1)的算法(辅助空间的规模和问题的输入规模无关)。引入堆栈的所谓非递归本质上还是递归,只不过原来由编译器做的事让你的程序来模拟实现了。不是所有的可计算问题都可以由递归转化为递推的。例如著名的Ackermann函数,就没有递推算法,除非引入堆栈等辅助结构。

递归转迭代的方法:

尾递归:普通的线性递归比尾递归更加消耗资源。尾递归就是从最后开始计算, 每递归一次就算出相应的结果, 也就是说, 函数调用出现在调用者函数的尾部, 因为是尾部, 所以根本没有必要去保存任何局部变量. 直接让被调用的函数返回时越过调用者, 返回到调用者的调用者去.

一个尾递归函数很容易转化为迭代。

然而通常所见到的递归都不是尾递归形式,这时候我们可以想办法用等价变换将其变化为等价的尾递归形式。尾递归是最简单的一类直接可以转化为递推的递归算法,另外还有很多方法将递归转化为递推,例如利用Cooper变换,反演变换,T1,T2变换,C变换,RR变换等。

http://blog.youkuaiyun.com/politefish/article/details/4504798 迭代算法与递归算法的概念及区别
http://blog.sina.com.cn/s/blog_4d3f5a400100h9y0.html 
http://www.4ucode.com/Study/Topic/1910521 关于尾递归
http://www.cnblogs.com/fengjun/archive/2011/11/09.html


<think>好的,用户想了解递归迭代算法之间的主要差异及适用场景。首先,我需要回忆一下已有的知识,并结合提供的引用内容来构建回答。 首先,递归迭代都是控制结构,但实现方式不同。递归是通过函数自身调用来解决问题,而迭代使用循环结构。根据引用[1],递归迭代各有优缺点,适用于不同的场景。引用[3]提到递归适合自相似性、分治树形结构的问题,而迭代适合大规模数据性能要求高的场景。 接下来,我需要明确两者的差异点。根据引用[5],递归必须有一个基本情况作为终止条件,否则会导致无限递归。而迭代则通过循环条件来控制,可能更容易出现无限循环,但通常结构更简单。 在性能方面,引用[4]指出递归在n较大时执行时间远高于迭代,因为递归需要重复计算子问题,比如斐波那契数列的递归实现会有大量重复计算。而迭代可以通过存储中间结果来优化,比如动态规划。 内存使用方面,递归的堆栈开销较大,可能导致栈溢出,而迭代通常使用固定内存,更高效。例如,处理深度大的树结构时,递归可能有风险,这时迭代更安全。 适用场景方面,递归适合问题分解自然的场景,如树的遍历、分治算法迭代适合线性处理,如数组遍历、数值计算。 需要结合引用中的例子,比如引用[3]提到的树形结构适合递归,大规模数据适合迭代。同时引用[4]中的斐波那契数列例子说明递归的效率问题。 最后,总结差异选择建议,帮助用户根据具体问题选择合适的方法。确保回答结构清晰,分点说明,并引用相关文献支持。</think>### 递归迭代算法的主要差异及适用场景 #### 一、核心差异对比 1. **实现方式** - **递归**:通过函数自身调用分解问题,需定义明确的**基本情况(Base Case)**作为终止条件[^5]。例如阶乘计算: $$n! = n \times (n-1)! \quad (\text{当 } n=0 \text{ 时 } 0! = 1)$$ - **迭代**:使用循环结构(如`for`、`while`)重复执行代码块,通过循环变量控制过程。例如求计算: ```python sum = 0 for i in range(1, n+1): sum += i ``` 2. **性能与资源消耗** - **递归**:存在**重复计算****堆栈溢出风险**。例如斐波那契数列的递归实现会重复计算子问题,时间复杂度为$O(2^n)$[^4]。 - **迭代**:通常通过变量存储中间结果,时间复杂度更低(如斐波那契数列迭代实现为$O(n)$),且内存占用更稳定。 3. **代码可读性与维护性** - **递归**:代码简洁,更贴近数学定义(如汉诺塔问题)。 - **迭代**:逻辑更直接,适合线性流程(如数组遍历)。 --- #### 二、适用场景分析 | **场景特点** | **推荐方法** | **示例** | |----------------------|--------------|------------------------------| | 自相似性/分治结构 | 递归 | 快速排序、二叉树遍历 | | 树形/图结构处理 | 递归 | DOM树解析、迷宫路径搜索 | | 大规模数据/高性能需求 | 迭代 | 图像处理、数值模拟 | | 简单线性流程 | 迭代 | 数组求、线性搜索 | --- #### 三、选择建议 1. **优先选择递归**:当问题天然适合递归分解(如分治算法、回溯算法)且数据规模较小时。 2. **强制使用迭代**:当存在堆栈溢出风险(如深度超过$10^4$的递归需要严格性能优化时[^3]。 3. **混合策略**:部分场景可结合两者优势,例如通过**迭代实现深度优先搜索(DFS)**来避免递归堆栈限制。 --- #### 示例代码对比 **递归实现斐波那契数列**(简洁但低效): ```python def fib(n): if n <= 1: return n return fib(n-1) + fib(n-2) # 重复计算导致O(2^n)复杂度 ``` **迭代实现斐波那契数列**(高效): ```python def fib(n): a, b = 0, 1 for _ in range(n): a, b = b, a + b return a # 时间复杂度O(n) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值