程序算法艺术与实践:递归策略之递归,循环与迭代

众所周知,递归的实现是通过调用函数本身,函数调用的时候,每次调用时要做地址保存,参数传递等,这是通过一个递归工作栈实现的,同时影响效率的。递归是利用系统的堆栈保存函数当中的局部变量来解决问题的,而递归就是在栈处理栈上一堆的指针指向内存中的对象,这些对象一直不被释放,直到递归执行到最后一次后,才释放空间.

循环效率与递归效率

递归与循环是两种不同的解决问题的典型思路。当然也并不是说循环效率就一定比递归高,递归和循环是两码事,递归带有栈操作,循环则不一定,两个概念不是一个层次,不同场景做不同的尝试。

  递归算法 循环算法
优点 代码简洁、清晰,并且容易验证正确性。 速度快,结构简单
缺点 它的运行需要较多次数的函数调用,如果调用层数比较深,需要增加额外的堆栈处理(还有可能出现堆栈溢出的情况),比如参数传递需要压栈等操作,会对执行效率有一定影响。但是,对于某些问题,如果不使用递归,那将是极端难看的代码。 并不能解决所有的问题。有的问题适合使用递归而不是循环。如果使用循环并不困难的话,最好使用循环。

递归通常很直白地描述了一个求解过程,因此也是最容易被想到和实现的算法。循环其实和递归具有相同的特性(即:做重复任务),但有时,使用循环的算法并不会那么清晰地描述解决问题步骤。单从算法设计上看,递归和循环并无优劣之别。然而,在实际开发中,因为函数调用的开销,递归常常会带来性能问题,特别是在求解规模不确定的情况下。而循环因为没有函数调用开销,所以效率会比递归高。除少数编程语言对递归进行了优化外,大部分语言在实现递归算法时还是十分笨拙,由此带来了如何将递归算法转换为循环算法的问题。算法转换应当建立在对求解过程充分理解的基础上,有时甚至需要另辟蹊径。

  • 一般递归调用可以处理的算法,也通过循环去解决需要额外的低效处理。
  • 现在的编译器在优化后,对于多次调用的函数处理会有非常好的效率优化,效率未必低于循环。
  • 递归和循环两者完全可以互换。如果用到递归的地方可以很方便使用循环替换,而不影响程序的阅读,那么替换成递归往往是好的。(例如:求阶乘的递归实现与循环实现。)

要转换成为非递归,两步工作:第一步,可以自己建立一个堆栈保存这些局部变量,替换系统栈;第二步把对递归的调用转变为循环处理就可以了。递归使用的栈布局.首先,看一下系统栈和用户栈的用途。系统栈(也叫核心栈、内核栈)是内存中属于操作系统空间的一块区域,其主要用途为:保存中断现场,对于嵌套中断,被中断程序的现场信息依次压入系统栈,中断返回时逆序弹出;以及保存操作系统子程序间相互调用的参数、返回值、返回点以及子程序(函数)的局部变量。用户栈是用户进程空间中的一块区域,用于保存用户进程的子程序间相互调用的参数、返回值、返回点以及子程序(函数)的局部变量。我们编写的递归程序属于用户程序,因此使用的是用户栈。

循环与迭代

来自<<为之漫笔>>对这几个概念的一段理解:"loop、iterate、traversal and recursion".这几个词是计算机技术书中经常会出现的几个词汇,众所周知,这几个词分别翻译为:循环、迭代、遍历和递归。乍一看,这几个词好像都与重复(repeat)有关,但有的又好像不完全是重复的意思。那么这几个词到底各是什么含义,有什么区别和联系呢?即:

  • 循环(loop),指的是在满足条件的情况下,重复执行同一段代码。比如,while语句。
  • 迭代(iterate),指的是按照某种顺序逐个访问列表中的每一项。比如,for语句。
  • 遍历(traversal),指的是按照一定的规则访问树形结构中的每个节点,而且每个节点都只访问一次。
  • 递归(recursion),指的是一个函数不断调用自身的行为。比如,以编程方式输出著名的斐波纳契数列。

这几个概念之间的区别其实就比较清楚了。至于它们之间的联系,严格来讲,它们似乎都属于算法的范畴。换句话说,它们只不过是解决问题的不同手段和方式,而本质上则都是计算机编程中达成特定目标的途径。

迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。利用迭代算法解决问题,需要三个方面的.第一 确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量;第二 建立迭代关系式。所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。第三 对迭代过程进行控制。在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。迭代过程的控制通常可分为两种情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数无法确定。对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;对于后一种情况,需要进一步分析出用来结束迭代过程的条件。经典的迭代的算法问题如兔子产子问题和上楼梯的走法问题.

迭代与循环,先从字面上看:迭代:“迭”:轮流,轮番,替换,交替,更换。“代”:代替。所以迭代的意思是:变化的循环,这种变化就是轮番代替,轮流代替。而循环:不变的重复。或者迭代是循环的一种,循环体代码分为固定循环体,和变化的循环体。

固定的循环如:

for(int  i=0; i < 8; i++){
	echo ‘Welcome to AlgrithemMagic‘;
}

实现迭代:

int sum = 0;
for(int i = 1; i <= 1000; i++ ){
	sum +=  i;
}

上面的迭代是常见的递增式迭代。类似的还有递减式迭代,递乘式迭代。迭代的好处:迭代减少了冗余代码,提高了代码的利用率和动态性。

循环、迭代与递归

递归算法与迭代算法的设计思路区别在于:函数或算法是否具备收敛性,当且仅当一个算法存在预期的收敛效果时,采用递归算法才是可行的,否则,就不能使用递归算法。当然,从理论上说,所有的递归函数都可以转换为迭代函数,反之亦然,然而代价通常都是比较高的。但从算法结构来说,递归声明的结构并不总能够转换为迭代结构,原因在于结构的引申本身属于递归的概念,用迭代的方法在设计初期根本无法实现,这就像动多态的东西并不总是可以用静多态的方法实现一样。这也是为什么在结构设计时,通常采用递归的方式而不是采用迭代的方式的原因,一个极典型的例子类似于链表,使用递归定义及其简单,但对于内存定义(数组方式)其定义及调用处理说明就变得很晦涩,尤其是在遇到环链、图、网格等问题时,使用迭代方式从描述到实现上都变得很不现实。

递归其实是方便了程序员难为了机器。它只要得到数学公式就能很方便的写出程序。优点就是易理解,容易编程。但递归是用栈机制实现的,每深入一层,都要占去一块栈数据区域,对嵌套层数深的一些算法,递归会力不从心,空间上会以内存崩溃而告终,而且递归也带来了大量的函数调用,这也有许多额外的时间开销。所以在深度大时,它的时空性就不好了。循环其缺点就是不容易理解,编写复杂问题时困难。优点是效率高。运行时间只因循环次数增加而增加,没什么额外开销。空间上没有什么增加。

局部变量占用的内存是一次性的,也就是O(1)的空间复杂度,而对于递归,每次函数调用都要压栈,那么空间复杂度是O(n),和递归次数呈线性关系。

递归程序改用循环实现的话,一般都是要自己维护一个栈的,以便状态的回溯。如果某个递归程序改用循环的时候根本就不需要维护栈,那其实这个递归程序这样写只是意义明显一些,不一定要写成递归形式。但很多递归程序就是为了利用函数自身在系统栈上的auto变量记录状态,以便回溯。原理上讲,所有递归都是可以消除的,代价就是可能自己要维护一个栈。而且我个人认为,很多情况下用递归还是必要的,它往往能把复杂问题分解成更为简单的步骤,而且很能反映问题的本质。

递归其实就是利用系统堆栈,实现函数自身调用,或者是相互调用的过程。在通往边界的过程中,都会把单步地址保存下来,知道等出边界,再按照先进后出的进行运算,这正如我们装木桶一样,每一次都只能把东西方在最上面,而取得时候,先放进取的反而最后取出。递归的数据传送也类似。但是递归不能无限的进行下去,必须在一定条件下停止自身调用,因此它的边界值应是明确的。就向我们装木桶一样,我们不能总是无限制的往里装,必须在一定的时候把东西取出来。比较简单的递归过程是阶乘函数,你可以去看一下。但是递归的运算方法,往往决定了它的效率很低,因为数据要不断的进栈出栈。但是递归作为比较基础的算法,它的作用不能忽视。

关于程序算法艺术与实践更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 12:17:15

程序算法艺术与实践:递归策略之递归,循环与迭代的相关文章

程序算法艺术与实践之二:函数的渐近的界

众所周知,算法所需的时间应当是随着其输入规模增长的,而输入规模与特定具体问题有关.对大多数问题来说其最自然的度量就是输入中的元素个数.算法的运行时间是指在特定输入时所执行的基本操作数.我们可以得到关于一个关于输入规模n的所需时间的函数.然而可以进一步简化算法的时间分析,我们进行进一步抽象,首先,忽略每条语句的真实代价,通过运行时间的增长率来度量一个算法在时间方面的表现.我们只考虑公式的最高次项,并忽略它的常数系数.本博文主要介绍一些相关的数学知识即:函数的渐近的界的定义与性质.常用的证明方法.

程序算法艺术与实践经典排序算法之Insertion Sort

插入排序(Insertion Sort)的基本思想是每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止. 基本思想与伪代码 经过j-1遍处理后,A[1..j-1]己排好序.第j遍处理仅将A[j]插入L[1..j-1]的适当位置,使得A[1..j]又是排好序的序列.要达到这个目的,我们可以用顺序比较的方法.首先比较A[j]和A[j-1],如果A[j-1]≤ A[j],则A[1..j]已排好序,第i遍处理就结束了:否则交换A[j]与A[j-1]的

程序算法艺术与实践关于 AlphaGo 论文的阅读笔记

这是Deepmind 公司在2016年1月28日Nature 杂志发表论文 <Mastering the game of Go with deep neural networks and tree search>,介绍了 AlphaGo 程序的细节.本博文是对这篇论文的阅读笔记. AlphaGo 神经网络构成 AlphaGo 总体上由两个神经网络构成,以下我把它们简单称为「两个大脑」,这并非原文中的提法,只是我的一个比喻. 第一个大脑(Policy Network)的作用是在当前局面下判断下一

算法--递归策略

本文地址:http://www.cnblogs.com/archimedes/p/algorithm-recursion.html,转载请注明源地址. 递归的概念与基本思想 一个函数.过程.概念或数学结构,如果在其定义或说明内部又直接或间接地出现有其本身的引用,则称它们是递归的或者是递归定义的.在程序设计中,过程或函数直接或者间接调用自己,就被称为递归调用. 递归的实现方法 递归是借助于一个递归工作栈来实现:递归=递推+回归: 递推:问题向一极推进,这一过程叫做递推:这一过程相当于压栈. 回归:

黑马程序员----java基础---递归概述、递归和循环的区别

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.递归函数,通俗的说就是函数本身自己调用自己... 如:n!=n(n-1)! 你定义函数f(n)=nf(n-1) 而f(n-1)又是这个定义的函数..这就是递归 定义:程序调用自身的编程技巧称为递归( recursion). 递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小

算法一看就懂之「 递归 」

之前的文章咱们已经聊过了「 数组和链表 」.「 堆栈 」和「 队列 」,今天咱们来看看「 递归 」,当然「 递归 」并不是一种数据结构,它是很多算法都使用的一种编程方法.它太普遍了,并且用它来解决问题非常的优雅,但它又不是那么容易弄懂,所以我特意用一篇文章来介绍它. 一.「 递归 」是什么? 递归 就是指函数直接或间接的调用自己,递归是基于栈来实现的.递归的经典例子就是 斐波拉契数列(Fibonacci).一般如果能用递归来实现的程序,那它也能用循环来实现.用递归来实现的话,代码看起来更清晰一些

用程序算法做人生选择

[原文链接] 每年一到要找工作的时候,我就能收到很多人给我发来的邮件,总是问我怎么选择他们的 offer,去腾讯还是去豆瓣,去外企还是去国内的企业,去创业还是去考研,来北京还是回老家,该不该去创新工场?该不该去 thoughtworks?……等等,等等.今年从 7 月份到现在,我收到并回复了 60 多封这样的邮件.我更多帮他们整理思路,帮他们明白自己最想要的是什么.(注:我以后不再回复类似的邮件了). 我深深地发现,对于我国这样从小被父母和老师安排各种事情长大的人,当有一天,父母和老师都跟不上的

算法艺术与信息学竞赛书摘

<算法艺术与信息学竞赛>这本书我详细看了1.1.1.2.1.3,之后就看得不是很懂了,所以还是把摘要写出来,方便让我知道到底能学到什么. 第一章 算法与数据结构 “数据结构+算法=程序设计” 从理论分析和实际应用两方面阐述了算法与数据结构的基本知识. 1.1 概括的叙述了算法.数据结构.以及计算理论的一些概念. 1.2从实例出发,概括的介绍了一些基本算法,包括美剧.贪心.递归.递推. 1.3介绍基本数据结构,包括线性表队列.栈.树.二叉树.以及图遍历与拓扑排序. 1.4介绍了一些实用数据结构,

机器学习算法与编程实践之中文文本分类

这周学习了机器学习算法与编程实践第二章--中文文本分类的部分内容.该章以文本挖掘为大背景,以文本分类算法为中心,详细介绍了中文文本分类项目的相关知识点. 一.文本挖掘与文本分类的概念 被普遍认可的文本挖掘的定义如下:文本挖掘是指从大量文本数据中抽取事先未知的.可理解的.最终可用的知识的过程,同时运用这些知识更好的组织信息以便将来参考. 文本挖掘的7个主要领域有:(1)搜索和信息检索,(2)文本聚类,(3)文本分类,(4)Web挖掘.(5)信息抽取,(6)自然语言处理,(7)概念提取. 而文本分类