`
hellobin
  • 浏览: 65467 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

深入理解递归

 
阅读更多

大家都知道,递归的本质和栈数据的存取很相似了,都是先进去,但是往往最后处理!再者对于递归函数的局部变量的存储是按照栈的方式去存的,对于每一层的递归函数在栈中都保存了本层函数的局部变量,一边该层递归函数结束时能够保存原来该层的数据!如图:

如上图递归式依次往下进行的,并且在该层递归函数还没结束即将进入下一层递归调用时,将会把该层函数中的局部变量保存起来,以供下次使用!
好了,以上是递归函数的数据存储方式,可是有时候我们又得抓头了,递归的话,有时候又很难理解,貌似总也想不通!

于是我又把每一层递归函数化分为三部分了,第一部分:是递归调用前的一些数据处理,判断以及递归结束判断(当然了结束条件肯定在递归调用前,要不每次递归就不会结束了),第二部分:就是递归函数本身了。而第三部分:当然就是递归函数的后续处理代码了!在这里我想我们得想明白一件事情了,每一层的函数都是在上一层递归函数结束时才返回的然后接着处理该层递归函数剩下的部分!例如如下代码:

 

#include<iostream>
#include<string>
using namespace std;

int i=0,j;
void reverse(string &s);
int main()
{
	string s;

	cin>>s;
	j=i=s.size();
	reverse(s);
	cout<<s<<endl;

	return 0;
}

void reverse(string &s)
{
	char ch;                    //..........第一部分 ..........
	i--;
	ch=s[i];
	cout<<ch<<endl;             //这里i是全局变量,而ch是局部变量会保存在栈中
	if(-1==i)
		return;                  
	reverse(s);                 //本身的递归看做第二部分
	                            //后续部分看做第三部分
	s[--j]=ch;               //这句当且仅当该递归函数中的reverse返回时 才执行
	cout<<ch<<endl;
}



在以上代码中,每一层只有当reverse()结束了才会接着处理下面的s[--j]=ch;代码,因为每一次递归进去的时候reverse()上面的代码都已经处理了,所以当递归返回时处理的自然就是reverse()下面的代码了,如此循环直到结束!不过我觉着最重要的还有一样就是有时候不必刻意去关注的那么细,也要有全局观,例如我们只需要知道函数reverse()是继续处理同样的功能,没必要再去想这个函数里面又是怎么样怎么样的,我感觉肯定会抓狂的!希望跟我一样纠结的朋友不在纠结递归了.........

 

另外,

 

递归的使用条件:

  存在一个递归调用的终止条件;

  每次递归的调用必须越来越靠近这个条件;只有这样递归才会终止,否则是不能使用递归的!

总之,在你使用递归来处理问题之前必须首先考虑使用递归带来的好处是否能补偿

  他所带来的代价!否则,使用迭代算法会比递归算法要高效。

递归的基本原理:

  1 每一次函数调用都会有一次返回.当程序流执行到某一级递归的结尾处时,它会转移到前一级递归继续执行.

  2 递归函数中,位于递归调用前的语句和各级被调函数具有相同的顺序.如打印语句 #1 位于递归调用语句前,它按照递归调用的顺序被执行了 4 次.

  3 每一级的函数调用都有自己的局部变量.

  4 递归函数中,位于递归调用语句后的语句的执行顺序和各个被调用函数的顺序相反.

  即位于递归函数入口前的语句,右外往里执行;位于递归函数入口后面的语句,由里往外执行。

  5 虽然每一级递归有自己的变量,但是函数代码并不会得到复制.

  6 递归函数中必须包含可以终止递归调用的语句.

一旦你理解了递归(理解递归,关键是脑中有一幅代码的图片,函数执行到递归函数入口时,就扩充一段完全一样的代码,执行完扩充的代码并return,继续执行前一次递归函数中递归函数入口后面的代码),阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务。如果你的每个步骤正确无误,你的限制条件设置正确,并且每次调用之后更接近限制条件,递归函数总是能正确的完成任务。

不算递归调用语句本身,到目前为止所执行的语句只是除法运算以及对quotient的值进行测试。由于递归调用这些语句重复执行,所以它的效果类似循环:当quotient的值非零时,把它的值作为初始值重新开始循环。但是,递归调用将会保存一些信息(这点与循环不同),也就好是保存在堆栈中的变量值。这些信息很快就会变得非常重要。

斐波那契数是典型的递归案例:

 

  Fib(0) = 0 [基本情况] Fib(1) = 1[基本情况]

  对所有n > 1的整数:Fib(n) = (Fib(n-1) + Fib(n-2))[递归定义]

 递归算法一般用于解决三类问题:

 

  (1)数据的定义是按递归定义的。(Fibonacci函数)

 

  (2)问题解法按递归算法实现。(回溯)

 

  (3)数据的结构形式是按递归定义的。(树的遍历,图的搜索)

 如:

 

  procedure a;

 

  begin

 

  a;

 

  end;

 

  这种方式是直接调用.

又如:

 

  procedure b;

 

  begin

 

  c;

 

  end;

 

  procedure c;

 

  begin

 

  b;

 

  end;

 

  这种方式是间接调用.

如何设计递归算法

 

  1.确定递归公式

 

  2.确定边界(终了)条件

 

Ref:

http://blog.csdn.net/zp032420/article/details/7422158

http://www.cnblogs.com/jnje/archive/2011/04/09/2010637.html

分享到:
评论

相关推荐

    acm递归算法总结竞赛

    通过学习“acm递归算法总结”,参赛者可以深入理解递归思想,提高解决复杂问题的能力,尤其是在面对时间限制和空间限制的ACM竞赛环境下。掌握好递归算法,对于提升编程能力,尤其是在算法设计和复杂问题求解方面具有...

    宏递归宏递归宏递归宏递归

    在实际编程中,虽然宏递归可以提供某些灵活性,但通常建议优先考虑使用函数递归或循环来解决问题,因为它们更易于理解和调试,且在运行时环境中有更好的支持。只有在编译时计算或避免运行时开销的需求特别强烈时,才...

    java 递归问题文档

    在编程领域,递归是一种强大的概念,它是指...这个文档提供了一个良好的学习平台,帮助读者深入理解递归,并通过实践应用到实际问题中。在学习过程中,记得结合实例和实际情况去思考,这样能够更好地领会递归的魅力。

    递归论书籍

    7. **计算复杂性理论**:虽然这不是递归论的直接内容,但递归理论为计算复杂性理论提供了基础,如P类和NP类问题的研究,都依赖于对可计算性的深入理解。 8. **递归函数的性质**:比如封闭性(如加法、乘法、取余等...

    递归(c#.net源码).rar

    首先,让我们深入理解递归的基本原理。递归是当一个函数在其定义中调用自身时发生的情况。这种调用通常伴随着一个或多个基本情况(base cases),这些情况可以直接返回结果,而无需进一步的递归。除此之外,还有递归...

    一个例题,递归示例,非常形像的示例

    总的来说,递归是编程中的重要概念,通过深入理解递归的工作方式,开发者可以解决许多复杂的问题。本例题提供的直观示例将有助于深化对递归的理解,对于初学者来说,这是一个很好的学习资源。通过实践和分析这样的...

    递归下降语法分析

    为了深入理解递归下降解析,我们需要查看源代码文件`递归下降语法分析.cpp`,它可能包含了具体的解析函数定义和实现。`example1.txt`和`example.txt`可以作为测试用例,帮助我们验证解析器是否正确地解析了输入的...

    易语言源码易语言子程序递归教程.rar

    总的来说,易语言子程序的递归教程将带你深入理解递归的概念,学习如何在易语言中编写递归子程序,并通过实例来实践和掌握这一技巧。这个教程对于任何想要提升易语言编程能力的人来说都是宝贵的资源,无论是初学者...

    经典算法之递归

    压缩包中的“递归模拟实现”可能包含上述算法的代码实现,通过对这些实现的学习,我们可以深入理解递归的思想,并掌握如何在实际项目中应用它们。 总之,递归是编程中一种重要的思维方式和工具,它能简化问题解决的...

    递归下降语法分析器

    递归下降语法分析器是编译原理中的一个重要概念,它是一种自顶向下的解析方法,主要用于解析源代码,将源程序转化为...通过阅读和学习这份实现,我们可以深入理解递归下降解析器的工作原理,并能应用于自己的项目中。

    delphi编写的数独递归算法

    总的来说,使用Delphi和递归算法来解决数独问题,不仅可以展示出Delphi的强大功能,也能让开发者深入了解递归思想在实际问题中的应用。通过熟练掌握这种方法,开发者能够构建出更多有趣的逻辑游戏和算法解决方案。

    递归程序

    首先,让我们深入理解递归的基本原理。递归程序由两个主要部分组成:基本情况(base case)和递归情况(recursive case)。基本情况是问题最简单的情况,可以直接求解,而不需要进一步的递归调用。递归情况则是将...

    递归实现字符串反向输出

    本文将通过一个具体的例子——使用C语言实现字符串的反向输出,来深入理解递归的基本概念及其应用。 #### 一、递归基础 递归(Recursion)是指在一个函数的定义或执行过程中直接或间接地调用自身的一种方法。递归...

    Python中递归算法的理解与应用实例(包含详细的完整的程序和数据)

    使用场景及目标:适合想要深入了解递归工作机理,学会正确有效地运用递归算法处理各种复杂情况的学习者。 其他说明:推荐学习者动手实现文章中的各个例子以加深理解,在实践过程中体验递归的强大威力的同时注意到其...

    递归算法实验

    本实验旨在帮助学生熟悉Java编程环境,并深入理解递归算法的原理和应用。 **一、实验目标** 1. **熟悉Java上机环境**:学习和掌握Java开发工具的使用,如Eclipse或IntelliJ IDEA,以及基本的代码调试技巧。 2. **...

    递归和非递归方式计算Ackerman函数

    通过阅读和理解这些代码,你可以深入理解递归和非递归算法的差异,以及如何优化处理高度递归的函数。 总结来说,递归和非递归计算Ackerman函数涉及到了计算机科学中的基本概念,包括递归算法、迭代解决方案以及数据...

    递归与Python Turtle分形树绘制详解(包含详细的完整的程序和数据)

    通过实际操作,帮助学习者深入理解递归的工作机制及其在现实世界编程问题中的应用。 适用于已经掌握了基本Python语法,并想进一步探索递归算法和技术的初中级程序员。 该教程特别适用于那些希望通过实例学习递归理论...

    递归树, 真的是画一棵树.

    在IT领域,递归是一种强大的编程技术,常用于解决复杂问题。递归树是递归算法的一种可视化表现形式,它能帮助我们理解递归过程,尤其...通过深入理解递归原理并熟练运用VB,开发者可以创造出更多类似的富有创意的项目。

    VB 2005 汉诺塔递归程序示例

    在VB 2005中实现汉诺塔的递归程序,我们可以深入理解递归算法及其在实际编程中的应用。 首先,我们要了解递归的基本概念。递归是函数或过程在执行过程中调用自身的一种方法。在汉诺塔问题中,递归非常自然地出现,...

    编译原理的各种程序,内含递归下降,词法分析的程序,以及报告

    首先,让我们深入理解递归下降解析。递归下降是一种自顶向下的解析技术,它利用函数的递归调用来解析输入的源代码。这种方法通常用于实现上下文无关文法的解析。在提供的"递归下降法).rar"文件中,可能包含了一些...

Global site tag (gtag.js) - Google Analytics