当前位置:文档之家› 递归算法的介绍

递归算法的介绍

递归算法的介绍
递归算法的介绍

递归应用实例介绍

姓名:周凡专业:计算机科学与技术09级5班学号:09999035 关键词递归汉诺塔斐波那契数列快速排序

递归之所以能作为一种算法在程序设计语言中广泛应用,主要在于采用递归编写程序能使程序变得简洁和清晰.。

一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。说得直接一点,递归就是在过程或函数里调用自身。

下面,从本人掌握的编程知识,介绍几个使用递归算法的实例。

汉诺塔问题是源于印度一个古老传说的益智玩具。上帝创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。如果考虑一下把64片金片,由一根针上移到另一根针上,并且始终保持上小下大的顺序。这需要多少次移动呢?这里需要递归的方法。假设有n片,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2^n-1。n=64时,

f(64)= 2^64-1=18446744073709551615

假如每秒钟一次,共需多长时间呢?一个平年365天有31536000 秒,闰年366天有31622400秒,平均每年31556952秒,计算一下,

18446744073709551615/31556952=584554049253.855年,显然这是人力所不能及的,但是使用递归算法可以很快的解决问题首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;

若n为奇数,按顺时针方向依次摆放 A C B。

(1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。

(2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

(3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。

汉诺塔汉诺塔问题的递归实现:

#include

void hanoi(int n,char A,char B,char C)

{

if(n==1)

{

printf("Move disk %d from %c to %c\n",n,A,C);

}

else

{

hanoi(n-1,A,C,B);

printf("Move disk %d from %c to %c\n",n,A,C);

hanoi(n-1,B,A,C);

}

}

main()

{

int n;

printf("请输入数字n以解决n阶汉诺塔问题:\n");

scanf("%d",&n);

hanoi(n,'A','B','C');

}

相比非递归算法而言,递归算法更加简洁,代码行数更少,节约了时间与空间。

斐波那契数列指的是这样一个数列:1、1、2、3、5、8、13、21、…… 这个数列从第三项开始,每一项都等于前两项之和。从第二项开始,每个奇数项的平方都比前后两项之积多1,每个偶数项的平方都比前后两项之积少1。

该问题我们同样可以利用递归算法进行解读,算法如下:

public class Fib {

public static void main(String[] args) {

System.out.println(f(20));

System.out.println(fx(20));

}

//递归方式

public static int f(int n) {

//参数合法性验证

if (n < 1) {

System.out.println("参数必须大于1!");

System.exit(-1);

}

if (n == 1 || n == 2) return 1;

else return f(n - 1) + f(n - 2);

}

快速排序的思想是:先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1, 处理结束.

程序如下:

program kspv;

const n=7;

type

arr=array[1..n] of integer;

var

a:arr;

i:integer;

procedure quicksort(var b:arr; s,t:integer);

var i,j,x,t1:integer;

begin

i:=s;j:=t;x:=b;

repeat

while (b[j]>=x) and (j>i) do j:=j-1;

if j>i then begin t1:=b; b:=b[j];b[j]:=t1;end;

while (b<=x) and (i

if i

until i=j;

b:=x;

i:=i+1;j:=j-1;

if s

if i

end;

begin

write('input data:');

for i:=1 to n do read(a);

writeln;

quicksort(a,1,n);

write('output data:');

for i:=1 to n do write(a:6);

writeln;

end.

由以上三个算法实例可以说明:

递归算法解决问题的特点:

(1) 递归就是在过程或函数里调用自身。

(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。(3)递归总体来说是以空间换时间,速度快,耗内存。非递归比较省内存,速度稍微慢些。

递归算法的优点和缺点都是如此鲜明,使得我们在使用的时候应该宏观把握,所谓能因敌变化而取胜者,是为神!

当编写递归例程的时候,关键是要牢记递归的四个基本法则:

(1)基准情形(base case)。必须总有某些基准情形不能用递归就能求解。

以下的一段函数就是无终止递归函数:

int bad(int n)

{

if (n==0)

return 0;

else

return bad(n/3+1)+n-1;

}

(2)不断推进(making progress)。对于那些需要递归求解的情形,递归调用必须总能够朝着基准情形的方向推进。

有些情况可能使得递归问题无法推进。例如查字典问题或环的遍历,此时必须使用一些相应的措施来避免这种情形的出现。

(3)设计原则(design rule)。假设所有的递归调用都能运行。

这是一条非常重要的法则,使得我们不必去追踪大量的递归调用。

(4)合成效益原则(compound interest rule)。在求解一个问题的同一实例时,切勿在不同的递归调用中作重复的工作。

对于初学者来说,递归算法的使用很简单,但是处理较多数时,容易造成溢出,还是谨慎把握为好!

高中信息技术 算法与程序设计-递归算法的实现教案 教科版

递归算法的实现 【基本信息】 【课标要求】 (三)算法与问题解决例举 1. 内容标准 递归法与问题解决 (1)了解使用递归法设计算法的基本过程。 (2)能够根据具体问题的要求,使用递归法设计算法、编写递归函数、编写程序、求解问题。 【教材分析】 “算法的程序实现”是《算法与程序设计》选修模块第三单元的内容,本节课是“递归算法的程序实现”,前面学习了用解析法解决问题、穷举法解决问题、在数组中查找数据、对数进行排序以及本节的前一小节知识点“什么是自定义函数”的学习,在学习自定义函数的基础上,学习递归算法的程序实现是自定义函数的具体应用,培养学生“自顶向下”、“逐步求精”的意识起着重要的作用。 『递归算法在算法的学习过程中是一个难点,在PASCAL和C语言等程序语言的学习过程中,往往是将其放在“函数与过程”这一章节中来讲解的。递归算法的实现也是用函数或是过程的自我调用来实现的。从这一点上来讲,作者对教材的分析与把握是准确的,思路是清晰的,目标是明确的。』 【学情分析】 教学对象是高中二年级学生,前面学习了程序设计的各种结构,在学习程序设计各种结构的应用过程中培养了用计算机编程解决现实中问题的能力,特别是在学习循环语句的过程中,应用了大量的“递推”算法。前一节课学习了如何自定义函数,在此基础上学习深入学习和体会自定义函数的应用。以递推算法的逆向思维进行求解问题,在学习过程中体会递归算法的思想过程。多维度的思考问题和解决问题是提高学生的学习兴趣关键。 『递归算法的本质是递推,而递推的实现正是通过循环语句来完成的。作者准确把握了学生前面的学习情况,对递归算法的本质与特征也分析的很透彻,可以说作者对教学任务的分析是很成功的,接来就要看,在成功分析的基础上作者是如何通过设计教学来解决教学难点的了。』 【教学目标】

递归算法详解

递 归 冯文科 一、递归的基本概念。 一个函数、概念或数学结构,如果在其定义或说明内部直接或间接地出现对其本身的引 用,或者是为了描述问题的某一状态,必须要用至它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自己来定义自己的方法,称之为递归或递归定义。在程序设计中,函数直接或间接调用自己,就被称为递归调用。 二、递归的最简单应用:通过各项关系及初值求数列的某一项。 在数学中,有这样一种数列,很难求出它的通项公式,但数列中各项间关系却很简单,于是人们想出另一种办法来描述这种数列:通过初值及n a 与前面临近几项之间的关系。 要使用这样的描述方式,至少要提供两个信息:一是最前面几项的数值,一是数列间各项的关系。 比如阶乘数列 1、2、6、24、120、720…… 如果用上面的方式来描述它,应该是: ???>==-1 ,1,11n na n a n n 如果需要写一个函数来求n a 的值,那么可以很容易地写成这样:

这就是递归函数的最简单形式,从中可以明显看出递归函数都有的一个特点:先处理一 些特殊情况——这也是递归函数的第一个出口,再处理递归关系——这形成递归函数的第二个出口。 递归函数的执行过程总是先通过递归关系不断地缩小问题的规模,直到简单到可以作为 特殊情况处理而得出直接的结果,再通过递归关系逐层返回到原来的数据规模,最终得出问题的解。 以上面求阶乘数列的函数)(n f 为例。如在求)3(f 时,由于3不是特殊值,因此需要计 算)2(*3f ,但)2(f 是对它自己的调用,于是再计算)2(f ,2也不是特殊值,需要计算 )1(*2f ,需要知道)1(f 的值,再计算)1(f ,1是特殊值,于是直接得出1)1(=f ,返回上 一步,得2)1(*2)2(==f f ,再返回上一步,得62*3)2(*3)3(===f f ,从而得最终解。 用图解来说明,就是 下面再看一个稍复杂点的例子。 【例1】数列}{n a 的前几项为

递归算法详解

递归算法详解 C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算开始的函数递归。导致读过这本经书的同学们,看到阶乘计算第一个想法就是递归。但是在阶乘的计算里,递归并没有提供任何优越之处。在菲波那契数列中,它的效率更是低的非常恐怖。 这里有一个简单的程序,可用于说明递归。程序的目的是把一个整数从二进制形式转换为可打印的字符形式。例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,和‘7’。就如在printf函数中使用了%d格式码,它就会执行类似处理。 我们采用的策略是把这个值反复除以10,并打印各个余数。例如,4267除10的余数是7,但是我们不能直接打印这个余数。我们需要打印的是机器字符集中表示数字‘7’的值。在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获得正确的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。‘0’的ASCII码是48,所以我们用余数加上‘0’,所以有下面的关系: ‘0’+ 0 =‘0’ ‘0’+ 1 =‘1’ ‘0’+ 2 =‘2’ ... 从这些关系中,我们很容易看出在余数上加上‘0’就可以产生对应字符的代码。接着就打印出余数。下一步再取商的值,4267/10等于426。然后用这个值重复上述步骤。 这种处理方法存在的唯一问题是它产生的数字次序正好相反,它们是逆向打印的。所以在我们的程序中使用递归来修正这个问题。 我们这个程序中的函数是递归性质的,因为它包含了一个对自身的调用。乍一看,函数似乎永远不会终止。当函数调用时,它将调用自身,第2次调用还将调用自身,以此类推,似乎永远调用下去。这也是我们在刚接触递归时最想不明白的事情。但是,事实上并不会出现这种情况。 这个程序的递归实现了某种类型的螺旋状while循环。while循环在循环体每次执行时必须取得某种进展,逐步迫近循环终止条件。递归函数也是如此,它在每次递归调用后必须越来越接近某种限制条件。当递归函数符合这个限制条件时,它便不在调用自身。 在程序中,递归函数的限制条件就是变量quotient为零。在每次递归调用之前,我们都把quotient除以10,所以每递归调用一次,它的值就越来越接近零。当它最终变成零时,递归便告终止。 /*接受一个整型值(无符号0,把它转换为字符并打印它,前导零被删除*/

算法设计及分析递归算法典型例题

算法递归典型例题 实验一:递归策略运用练习 三、实验项目 1.运用递归策略设计算法实现下述题目的求解过程。 题目列表如下: (1)运动会开了N天,一共发出金牌M枚。第一天发金牌1枚加剩下的七分之一枚,第二天发金牌2枚加剩下的七分之一枚,第3天发金牌3枚加剩下的七分之一枚,以后每天都照此办理。到了第N天刚好还有金牌N枚,到此金牌全部发完。编程求N和M。 (2)国王分财产。某国王临终前给儿子们分财产。他把财产分为若干份,然后给第一个儿子一份,再加上剩余财产的1/10;给第二个儿子两份,再加上剩余财产的1/10;……;给第i 个儿子i份,再加上剩余财产的1/10。每个儿子都窃窃自喜。以为得到了父王的偏爱,孰不知国王是“一碗水端平”的。请用程序回答,老国王共有几个儿子?财产共分成了多少份? 源程序: (3)出售金鱼问题:第一次卖出全部金鱼的一半加二分之一条金鱼;第二次卖出乘余金鱼的三分之一加三分之一条金鱼;第三次卖出剩余金鱼的四分之一加四分之一条金鱼;第四次卖出剩余金鱼的五分之一加五分之一条金鱼;现在还剩下11条金鱼,在出售金鱼时不能把金鱼切开或者有任何破损的。问这鱼缸里原有多少条金鱼? (4)某路公共汽车,总共有八站,从一号站发轩时车上已有n位乘客,到了第二站先下一半乘客,再上来了六位乘客;到了第三站也先下一半乘客,再上来了五位乘客,以后每到一站都先下车上已有的一半乘客,再上来了乘客比前一站少一个……,到了终点站车上还有乘客六人,问发车时车上的乘客有多少? (5)猴子吃桃。有一群猴子摘来了一批桃子,猴王规定每天只准吃一半加一只(即第二天吃剩下的一半加一只,以此类推),第九天正好吃完,问猴子们摘来了多少桃子? (6)小华读书。第一天读了全书的一半加二页,第二天读了剩下的一半加二页,以后天天如此……,第六天读完了最后的三页,问全书有多少页? (7)日本著名数学游戏专家中村义作教授提出这样一个问题:父亲将2520个桔子分给六个儿子。分完后父亲说:“老大将分给你的桔子的1/8给老二;老二拿到后连同原先的桔子分1/7给老三;老三拿到后连同原先的桔子分1/6给老四;老四拿到后连同原先的桔子分1/5给老五;老五拿到后连同原先的桔子分1/4给老六;老六拿到后连同原先的桔子分1/3给老大”。结果大家手中的桔子正好一样多。问六兄弟原来手中各有多少桔子? 四、实验过程 (一)题目一:…… 1.题目分析 由已知可得,运动会最后一天剩余的金牌数gold等于运动会举行的天数由此可倒推每一 天的金牌剩余数,且每天的金牌数应为6的倍数。 2.算法构造 设运动会举行了N天, If(i==N)Gold[i]=N; Else gold[i]=gold[i+1]*7/6+i;

递归算法实例C源码

玩转算法与数据结构之递归算法 —HIT2000鲁天伟 递归算法在数据结构的树,图程序中都有应用。那么什么是递归算法呢。其实就是函数的自我调用。循环的在作一件事,把一个问题分成了可以重复的子问题去处理。递归这个词有两层含义,即递去和归来。递去,就是函数一层一层的在调用自己,我们在这里定义调用自己的函数为父函数,被调用的是子函数。父与子是个相对概念(参照二叉树中父结点与子结点来理解)。递去,何时结束呢,是要设定一个结束条件。那么这种结束条件的设置,第一种是设全局变量,全局变量随着每次自我调用在变化,当全局变量达到指定值或是全局变量参与的计算达到某个指定的值时结束。第二种是形参变量在被调用时达到指定值或形参参与的计算达到某个值时结束。第三种是当不满足自我调用条件时结束。这三种结束条件结合程序的需要可以组合使用。归来是指调用到某一次时,子程序执行结束了,子函数一层一层的把程序的执行权返还给自己的父函数,父函数执行所调用子函数的下一条命令。简单的递归,是一个函数体中调用自己一次,复杂的是在函数体中调用自己多次。 举一个字符串逆序输出的简单递归调用的例子如下图。 图表 1 递归函数调用

1、字符串逆序输出问题:将一个长为4的字符串逆序输出。代码如下: #include #define MAXSIZE 4 char data[MAXSIZE]; Rverse(int n){ if(n=3,F(1)=1,F(2)=1 代码如下: #include int Fib(int N){ if(N<=1) return N; else return Fib(N-1)+Fib(N-2); }

递归算法与递归程序

一、教学目标 1、知识与技能 (1).认识递归现象。 (2).使用递归算法解决问题往往能使算法的描述乘法而易于表达 (3).理解递归三要素:每次递归调用都要缩小规模;前次递归调用为后次作准备:递归调用必须有条件进行。 (4).认识递归算法往往不是高效的算法。 (5).了解递归现象的规律。 (6).能够设计递归程序解决适用于递归解决的问题。 (7).能够根据算法写出递归程序。 (8).了解生活中的递归现象,领悟递归现象的既有重复,又有变化的 特点,并 且从中学习解决问题的一种方法。 2、方法与过程 本节让同学们玩汉诺塔的游戏,导入递归问题,从用普通程序解决斐波那契的兔子问题入手,引导学生用自定义了一个以递归方式解决的函数过程解决问题,同时让同学们做三个递归练习,巩固提高。然后让学生做练习(2)和练习(3)这两道题目的形式相差很远,但方法和答案却是完全相同的练习,体会其中的奥妙,加深对递归算法的了解。最后用子过程解决汉诺塔的经典问题。 3、情感态度和价值观 结合高中生想象具有较强的随意性、更富于现实性的身心发展特点,综合反映出递归算法的特点,以及递归算法解答某些实践问题通常得很简洁,从而激发学生对程序设计的追求和向往。 二、重点难点 1、教学重点 (1)了解递归现象和递归算法的特点。

(2)能够根据问题设计出恰当的递归程序。 2、教学难点 (1)递归过程思路的建立。 (2)判断问题是否适于递归解法。 (3)正确写出递归程序。 三、教学环境 1、教材处理 教材选自《广东省普通高中信息技术选修一:算法与程序设计》第四章第五节,原教材的编排是以本节以斐波那契的兔子问题引人,导出递归算法,从而自定义了一个以递归方式解决的函数过程。然后利用子过程解决汉诺塔的经典问题。 教材经处理后,让同学们玩汉诺塔的游戏,导入递归问题,从用普通程序解决斐波那契的兔子问题入手,引导学生用自定义了一个以递归方式解决的函数过程解决问题,同时让同学们做三个递归练习,巩固提高。然后让学生做练习(2)和练习(3)这两道题目的形式相差很远,但方法和答案却都是完全相同的练习,体会其中的奥妙,加深对递归算法的了解。最后用子过程解决汉诺塔的经典问题。 教学方法采用讲解、探究、任务驱动和学生自主学习相结合 2、预备知识 学生已掌握了用计算机解决问题的过程,掌握了程序设计基础,掌握了解析法、穷举法、查找法、排序法设计程序的技巧。 3、硬件要求 建议本节课在多媒体电脑教室中完成,最好有广播教学系统或投影仪,为拓展学习,学生机应允许上互联网。 4、所需软件 学生机要安装VB6.0或以上版本。 5、所需课时 2课时(90分钟)

递归算法的优缺点

○1优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。 ○2缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。 边界条件与递归方程是递归函数的二个要素 应用分治法的两个前提是问题的可分性和解的可归并性 以比较为基础的排序算法的最坏倩况时间复杂性下界为0(n·log2n)。 回溯法以深度优先的方式搜索解空间树T,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树T。 舍伍德算法设计的基本思想: 设A是一个确定性算法,当它的输入实例为x时所需的计算时间记为tA(x)。设Xn是算法A的输入规模为n的实例的全体,则当问题的输入规模为n时,算法A所需的平均时间为 这显然不能排除存在x∈Xn使得的可能性。希望获得一个随机化算法B,使得对问题的输入规模为n的每一个实例均有 拉斯维加斯( Las Vegas )算法的基本思想: 设p(x)是对输入x调用拉斯维加斯算法获得问题的一个解的概率。一个正确的拉斯维加斯算法应该对所有输入x均有p(x)>0。 设t(x)是算法obstinate找到具体实例x的一个解所需的平均时间 ,s(x)和e(x)分别是算法对于具体实例x求解成功或求解失败所需的平均时间,则有: 解此方程可得:

蒙特卡罗(Monte Carlo)算法的基本思想: 设p是一个实数,且1/2

递归算法工作栈的变化详解

通常,一个函数在调用另一个函数之前,要作如下的事情:a)将实在参数,返回地址等信息传递给被调用函数保存; b)为被调用函数的局部变量分配存储区;c)将控制转移到被调函数的入口. 从被调用函数返回调用函数之前,也要做三件事情:a)保存被调函数的计算结果;b)释放被调函数的数据区;c)依照被调函数保存的返回地址将控制转移到调用函数.所有的这些,不论是变量还是地址,本质上来说都是"数据",都是保存在系统所分配的栈中的. ok,到这里已经解决了第一个问题:递归调用时数据都是保存在栈中的,有多少个数据需要保存就要设置多少个栈,而且最重要的一点是:控制所有这些栈的栈顶指针都是相同的,否则无法实现同步. 下面来解决第二个问题:在非递归中,程序如何知道到底要转移到哪个部分继续执行?回到上面说的树的三种遍历方式,抽象出来只有三种操作:访问当前结点,访问左子树,访问右子树.这三种操作的顺序不同,遍历方式也不同.如果我们再抽象一点,对这三种操作再进行一个概括,可以得到:a)访问当前结点:对目前的数据进行一些处理;b)访问左子树:变换当前的数据以进行下一次处理;c)访问右子树:再次变换当前的数据以进行下一次处理(与访问左子树所不同的方式). 下面以先序遍历来说明: void preorder_recursive(Bitree T) /* 先序遍历二叉树的递归算法*/ { if (T) { visit(T); /* 访问当前结点*/ preorder_recursive(T->lchild); /* 访问左子树*/ preorder_recursive(T->rchild); /* 访问右子树*/ } } visit(T)这个操作就是对当前数据进行的处理, preorder_recursive(T->lchild)就是把当前数据变换为它的左子树,访问右子树的操作可以同样理解了. 现在回到我们提出的第二个问题:如何确定转移到哪里继续执行?关键在于一下三个地方:a)确定对当前数据的访问顺序,简单一点说就是确定这个递归程序可以转换为哪种方式遍历的树结构;b)确定这个递归函数转换为递归调用树时的分支是如何划分的,即确定什么是这个递归调用树的"左子树"和"右子树"c)确定这个递归调用树何时返回,即确定什么结点是这个递归调用树的"叶子结点".

04.递归算法讲解

1.用递归法计算n! 【讲解】 递归是算法设计中的一种基本而重要的算法。递归方法即通过函数或过程调用自身将问题转化为本质相同但规模较小的子问题,是分治策略的具体体现。 递归方法具有易于描述、证明简单等优点,在动态规划、贪心算法、回溯法等诸多算法中都有着极为广泛的应用,是许多复杂算法的基础。 递归概述 一个函数在它的函数体内调用它自身称为递归(recursion)调用。是一个过程或函数在其定义或说明中直接或间接调用自身的一种方法,通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。 使用递归要注意以下几点: (1)递归就是在过程或函数里调用自身; (2)在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。 例如有函数r如下: int r(int a) { b=r(a?1); return b; } 这个函数是一个递归函数,但是运行该函数将无休止地调用其自身,这显然是不正确的。为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回。 构造递归方法的关键在于建立递归关系。这里的递归关系可以是递归描述的,也可以是递推描述的。 例4-1 用递归法计算n!。 n!的计算是一个典型的递归问题。使用递归方法来描述程序,十分简单且易于理解。 (1)描述递归关系 递归关系是这样的一种关系。设{U 1,U 2 ,U 3 ,…,U n ,…}是一个序列,如果从某一项k开始, U n 和它之前的若干项之间存在一种只与n有关的关系,这便称为递归关系。 注意到,当n≥1时,n!=n*(n?1)!(n=0时,0!=1),这就是一种递归关系。对于特定的k!,它只与k与(k?1)!有关。 (2)确定递归边界 在步骤1的递归关系中,对大于k的U n 的求解将最终归结为对U k 的求解。这里的U k 称 为递归边界(或递归出口)。在本例中,递归边界为k=0,即0!=1。对于任意给定的N!,程序将最终求解到0!。 确定递归边界十分重要,如果没有确定递归边界,将导致程序无限递归而引起死循环。例如以下程序: #include int f(int x) { return(f(x?1));}

实验1:循环与递归算法实验

实验一:循环与递归算法的应用 【实验目的】 1.掌握循环、递归算法的基本思想、技巧和效率分析方法。 2.熟练掌握循环和递归的设计要点,清楚循环和递归的异同。 3.学会利用循环、递归算法解决实际问题。 【实验内容】 1. 问题描述: (1)题目一:打印图形 编程打印如下图所示的N阶方阵。 1 3 6 10 15 2 5 9 14 4 8 13 7 12 11 (2)题目二:计算前n项和 根据参数n,计算1+2+……+n。 要求:用循环和递归分别实现 (3)题目三:回文判断 判断s字符串是否为“回文”的递归程序。 2. 数据输入:个人设定,由键盘输入。 3. 要求: (1)上述题目一、二必做,题目三选做; (2)独立完成实验及实验报告。 【具体实现过程】 题目一: 【算法分析】 通过两个for循环控制数字的输出。 【实现代码】

#include int main() { int i,j,k,n,l,middle,temp; printf("请输入n的大小\n"); scanf("%d",&n); k = 1; temp = 0; middle = 0; for(i=1;i<=n;i++) { middle = i+1; k += temp; printf("%d ",k); l = k; for(j=n;j>0;j--) { if(j==1) printf("\n"); else { l += middle; printf("%d ",l); middle++; } } temp++; n--; } return 0; }

题目二: 【算法分析】 定义一个sum函数求和,把求出的新值赋给sum,最后求得的值即为前n项和。【实现代码】 递归 #include "stdio.h" int fun(int num) { int sum; if( num==1) sum=1; else sum=num+fun(num-1); return sum; } void main() { int n,s; printf("n="); scanf("%d",&n); s=fun(n); printf("s=%d\n",s); }

递归算法详解完整版

递归算法详解标准化管理处编码[BBX968T-XBB8968-NNJ668-MM9N]

递归 冯文科一、递归的基本概念。 一个函数、概念或数学结构,如果在其定义或说明内部直接或间接地出现对其本身的引用,或者是为了描述问题的某一状态,必须要用至它的上一状态,而描述上一状态,又必须用到它的上一状态……这种用自己来定义自己的方法,称之为递归或递归定义。在程序设计中,函数直接或间接调用自己,就被称为递归调用。 二、递归的最简单应用:通过各项关系及初值求数列的某一项。 在数学中,有这样一种数列,很难求出它的通项公式,但数列中各项间关系却很简 a与前面临近几项之间的关单,于是人们想出另一种办法来描述这种数列:通过初值及 n 系。 要使用这样的描述方式,至少要提供两个信息:一是最前面几项的数值,一是数列间各项的关系。 比如阶乘数列 1、2、6、24、120、720…… 如果用上面的方式来描述它,应该是: a的值,那么可以很容易地写成这样: 如果需要写一个函数来求 n

这就是递归函数的最简单形式,从中可以明显看出递归函数都有的一个特点:先处理一些特殊情况——这也是递归函数的第一个出口,再处理递归关系——这形成递归函数的第二个出口。 递归函数的执行过程总是先通过递归关系不断地缩小问题的规模,直到简单到可以作为特殊情况处理而得出直接的结果,再通过递归关系逐层返回到原来的数据规模,最终得出问题的解。 以上面求阶乘数列的函数) f为例。如在求)3(f时,由于3不是特殊值,因此需 (n 要计算)2( 3f,但)2(f是对它自己的调用,于是再计算)2(f,2也不是特殊值,需要计 * 算)1( f,返回 )1(= 2f,需要知道)1(f的值,再计算)1(f,1是特殊值,于是直接得出1 * 上一步,得2 3 * )2( )3(= = f,从而得最终 =f )1( 3 2 * * )2(= =f 2 f,再返回上一步,得6 解。 用图解来说明,就是

递归算法的优缺点

递归算法的优缺点: ○ 1优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。 ○2缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。 边界条件与递归方程是递归函数的二个要素 应用分治法的两个前提是问题的可分性和解的可归并性 以比较为基础的排序算法的最坏倩况时间复杂性下界为0(n·log2n)。 回溯法以深度优先的方式搜索解空间树T ,而分支限界法则以广度优先或以最小耗费优先的方式搜索解空间树T 。 舍伍德算法设计的基本思想: 设A 是一个确定性算法,当它的输入实例为x 时所需的计算时间记为tA(x)。设Xn 是算法A 的输入规模为n 的实例的全体,则当问题的输入规模为n 时,算法A 所需的平均时间为 这显然不能排除存在x ∈Xn B ,使得对问题的输入规模为n 拉斯维加斯( Las Vegas )算法的基本思想: 设p(x) 是对输入x 调用拉斯维加斯算法获得问题的一个解的概率。一个正确的拉斯维加斯算法应该对所有输入x 均有p(x)>0。 设t(x)是算法obstinate 找到具体实例x 的一个解所需的平均时间 ,s(x)和e(x)分别是算法对于具体实例x 蒙特卡罗(Monte Carlo)算法的基本思想: 设p 是一个实数,且1/2

c++,使用欧几里得算法计算两个数的最大公约数,分别用递推和递归两种算法实现5

实验九 一、实验内容 教材3.9 定义递归函数实现下面的Ackman函数 n+1 m=0 Acm(m,n)= Acm(m-1,1) n=0 Acm(m-1,Acm(m,n-1)) n>0,m>0 教材3.10 用递归法实现勒让德多项式: 1 n=0 Pn= x n=1 ((2n-1)xPn-1(x)-(n-1)Pn-2(x))/n 教程p24 使用欧几里得算法计算两个数的最大公约数,分别用递推和递归两种算法实现 教程p26 编程:将上题以多文件方式组织,在area.h中声明各个area()函数原型,在area.cpp文件中定义函数,然后在Exp9_2中包含area.h,定义main() 函数并执行。 二、实验目的 1、掌握函数的嵌套调用好递归调用 2、掌握递归算法 3、了解内联函数、重载函数、带默认参函数的定义及使用方法 4、掌握程序的多文件组织 5、掌握编译预处理的内容,理解带参数宏定义与函数的区别 三、实验步骤 教材3.9 定义递归函数实现下面的Ackman函数 n+1 m=0 Acm(m,n)= Acm(m-1,1) n=0 Acm(m-1,Acm(m,n-1)) n>0,m>0 教材3.10用递归法实现勒让德多项式: 1 n=0 Pn= x n=1 ((2n-1)xPn-1(x)-(n-1)Pn-2(x))/n 教程p24 使用欧几里得算法计算两个数的最大公约数,分别用递推和递归两种算法实现 教程p26 编程:将上题以多文件方式组织,在area.h中声明各个area()函数原型,在area.cpp文件中定义函数,然后在Exp9_2中包含area.h,定义main() 函数并执行。 四、实验数据及处理结果

讲义一 递归的消除

递归算法具有两个特性: (1) 递归算法是一种分而治之、把复杂问题分解为简单问题的求解问题方法,对求解某些复杂问题,递归算法分析方法是有效的。 (2)递归算法的时间效率差,其时间效率低。 为此,对求解某些问题时,我们希望用递归算法分析问题,用非递归算法求解具体问题; 消除递归原因: 其一:有利于提高算法时空性能,因为递归执行时需要系统提供隐式栈实现递归,效率低,费时。 其二:无应用递归语句的语言设施环境条件,有些计算机语言不支持递归功能,如FORTRAN 、C 语言中无递归机制 。 其三,递归算法是一次执行完,这在处理有些问题时不合适,也存在一个把递归算法转化为非递归算法的需求。 理解递归机制,是掌握递归程序技能必要前提。消除递归要基于对问题的分析,常用的有两类消除递归方法。 一类是简单递归问题的转换,对于尾递归和单向递归的算法,可用循环结构的算法替代。 另一类是基于栈的方式,即将递归中隐含的栈机制转化为由用户直接控制的明显的栈。利用堆栈保存参数,由于堆栈的后进先出特性吻合递归算法的执行过程,因而可以用非递归算法替代递归算法。 在大量复杂的情况下,递归的问题无法直接转换成循环,需要采用工作栈消除递归。工作栈提供一种控制结构,当递归算法进层时需要将信息保留;当递归算法出层时需要从栈区退出信息。 栈及其应用 一.栈的特点: 栈是一种线性表,对于它所有的插入和删除都限制在表的 同一端进行,这一端叫做栈的“顶”,另一端则叫做栈的“底”, 其操作特点是“后进先出”。 二.栈的抽象数据定义: 1、栈的数组表示 — 顺序栈 s 为栈、p 为指向栈顶的指针 type stack=record data:array[1..m] of datatype; p:0..m end; var s:stack; 2、栈的链接表示 — 链式栈 bottom

n!非递归算法的设计与实现

数据结构课程设计 设计说明书 n!非递归算法的设计与实现 学生姓名赵娜 学号1021024042 班级信管102班成绩 指导教师曹记东 数学与计算机科学学院 2012 年 3 月 3 日

数据结构课程设计评阅书 注:指导教师成绩60%,答辩成绩40%,总成绩合成后按五级制记入。

课程设计任务书 2011—2012学年第2学期 专业:计算机科学与技术学号:1021024042 姓名:赵娜 课程设计名称:数据结构课程设计 设计题目:n!非递归算法的设计与实现 完成期限:自2012 年 2 月20 日至2012 年 3 月 3 日共 2 周 设计内容: 利用非递归算法实现n!的计算,在设计过程中应注意n值大小与数据类型表数范围之间的关系,并尽可能求出较大n值的阶乘。 要求: 1)阐述设计思想,画出流程图; 2)说明测试方法,写出完整的运行结果; 3)从时间、空间对算法分析; 4)较好的界面设计; 5)编写课程设计报告。 以上要求中第一个阶段的任务完成后,先将设计说明书的草稿交指导老师面审,审查合格后方可进入后续阶段的工作。设计工作结束后,经指导老师验收合格后将设计说明书打印装订,并进行答辩。 指导教师(签字):教研室主任(签字): 批准日期:2012年 2 月20 日

摘要 设计了一个用非递归算法实现n!的软件,该软件具有计算从1到999之间整数的阶乘的运算的功能。本计算器采用VC++作为软件开发环境,采用数组存储运算的结果,用栈输出运算结果,用递推法实现了整数的阶乘运算,界面清晰,易于为用户所接受。 关键词:n!; 非递归;数组;栈

目录 1 课题描述 (1) 2 需求分析 (2) 3 概要设计 (3) 4 详细设计 (4) 5 程序编码 (8) 6 程序调试与测试 (10) 7 结果分析 (12) 8 总结 (13) 参考文献 (14)

(重要)递归(含代码执行过程解释)

递归算法详细分析-> C阅读(17418) C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算开始的函数递归。导致读过这本经书的同学们,看到阶乘计算第一个想法就是递归。但是在阶乘的计算里,递归并没有提供任何优越之处。在菲波那契数列中,它的效率更是低的非常恐怖。 这里有一个简单的程序,可用于说明递归。程序的目的是把一个整数从二进制形式转换为可打印的字符形式。例如:给出一个值4267,我们需要依次产生字符‘4’,‘2’,‘6’,和‘7’。就如在printf函数中使用了%d格式码,它就会执行类似处理。 我们采用的策略是把这个值反复除以10,并打印各个余数。例如,4267 除10的余数是7,但是我们不能直接打印这个余数。我们需要打印的是机器字符集中表示数字‘7’的值。在ASCII码中,字符‘7’的值是55,所以我们需要在余数上加上48来获得正确的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。‘0’的ASCII码是48,所以我们用余数加上‘0’,所以有下面的关系: ‘0’+ 0 =‘0’ ‘0’+ 1 =‘1’ ‘0’+ 2 =‘2’ ... 从这些关系中,我们很容易看出在余数上加上‘0’就可以产生对应字符的代码。接着就打印出余数。下一步再取商的值,4267/10等于426。然后用这个值重复上述步骤。 这种处理方法存在的唯一问题是它产生的数字次序正好相反,它们是逆向打印的。所以在我们的程序中使用递归来修正这个问题。 我们这个程序中的函数是递归性质的,因为它包含了一个对自身的调用。乍一看,函数似乎永远不会终止。当函数调用时,它将调用自身,第2次调用还将调用自身,以此类推,似乎永远调用下去。这也是我们在刚接触递归时最想不明白的事情。但是,事实上并不会出现这种情况。 这个程序的递归实现了某种类型的螺旋状while循环。while循环在循环体每次执行时必须取得某种进展,逐步迫近循环终止条件。递归函数也是如此,它在每次递归调用后必须越来越接近某种限制条件。当递归函数符合这个限制条件时,它便不在调用自身。

高中信息技术递归算法的实现教案 粤教版

《递归算法与递归程序》(一)教学设计 一、教材分析 “递归算法与递归程序”是广东教育出版社《算法与程序设计》选修1第四单元第五节的内容,前面学习了用解析法解决问题、穷举法解决问题、在数组中查找数据、对数进行排序,且在第二章中学习了自定义过程与函数。在前面学习的基础上,学习递归算法的程序实现是自定义函数的具体应用,在培养学生“自顶向下”、“逐步求精”的意识起着重要的作用。 二、学情分析 教学对象是高中二年级学生,前面学习了程序设计的各种结构与自定义函数(过程)及常用基础算法,在学习程序设计各种结构的应用过程中,培养了学生用计算机编程解决现实中的问题的能力。在学习循环语句的过程中,应用了大量的“递推”算法,在第二章中,学习了如何使用自定义函数,在此基础上深入学习和体会自定义函数的应用,以递推算法的逆向思维进行求解问题,在学习过程中体会递归算法的思想过程。多维度的思考问题和解决问题是提高学生的学习兴趣关键。 三、教学目标 知识与技能: 1、理解什么是递归算法,学会递归算法的思想分析问题 2、能够应用递归算法编程处理实际问题 过程与方法:学生参与讨论,通过思考、动手操作,体验递归算法的方法 情感态度与价值:结合数学中的实例,激发学生使用数学知识建模的意识,培养学生多维度的思考问题和解决问题。 四、教学重点与难点 重点:理解什么是递归算法 难点:学生用递归算法的思想分析问题 五、教学过程 进程教师活动学生活动设计意图 创设情境课堂导入: 师:今天我们先做一个小的智力题目 有4个人排成一队,问最后一个人的身高时,他 说比第3个人高2厘米;问第3个人的身高时, 他说比第2个人高2厘米;问第2个人的身高时, 他说比第1个人高2厘米;最后问第1个人的身 师生共同活动找 出递变规律 使用情境教学法 在此活动过程中能 让学生初步从活动 中体验“问题的发与 收”从而走进了递归 的思维模式,为进一

用递归法解决问题

用递归法解决问题 一、教材分析 “算法的程序实现”是高中信息技术教育出版社《算法与程序设计》选修模块第三单元的内容,本节课是“递归算法的程序实现”,前面学习了用解析法解决问题、穷举法解决问题、在数组中查找数据、对数进行排序以及本节的前一小节知识点“什么是自定义函数”的学习,,在学习自定义函数的基础上,学习递归算法的程序实现是自定义函数的具体应用,培养学生“自顶向下”、“逐步求精”的意识起着重要的作用。 课时安排:1课时 二、学情分析 教学对象是高中二年级学生,前面学习了程序设计的各种结构,在学习程序设计各种结构的应用过程中的培养了用计算机编程解决现实中的问题,特别的学习循环语句的过程中,应用了大量的“递推”算法。前一节课学习了如何自定义函数,在此基础上学习深入学习和体会自定义函数的应用。以递推算法的逆向思维进行求解问题,在学习过程中体会递归算法的思想过程。多维度的思考问题和解决问题是提高学生的学习兴趣关键。 三、教学目标 知识与技能: 1、理解什么是递归算法,学生用递归算法的思想分析问题 2、能够应用自定义函数方法实现递归算法的编程 过程与方法: 学生参与讨论,通过思考、动手操作,体验递归算法的方法 情感态度与价值: 结合数学中的实例,激发学生的数学建模的意识,培养学生多维度的思考问题和解决问题。 四、教学重点·难点 重点:理解什么是递归算法,学生用递归算法的思想分析问题 应用自定义函数方法实现递归算法的编程 难点:应用自定义函数方法实现递归算法的编程 五、教学过程

六、教学反思 从游戏的方式导入活动,充分的调动学生的思维,渐渐的走入了“递归的思维”模式,从而引出“猴子吃桃”,使用的前面活动(礼物是什么?)的思维,诱导学生进入了“递归”思想解题。学生阅读教材范例“裴波那契”,培养学生的自学能力、和知识迁移建构自我的知识体系。内化递归算法的实现,再由递归思维的逆向思维讨论“递推”的算法,进行比较计算机资源的耗费高,可读性差。为下一步导出结论做好了铺垫。 学好本节课的前提是:懂得自定义函数的使用方法,如果学生对自定义函数理解程度,是本节课效果是否得以完成的关键

用递归法解决问题

3.5用递归法解决问题 【教材分析】 “用递归法解决问题”是《算法与程序设计》第三章第5节的内容,学业水平测试对本节内容也达到了B级要求,本节内容是在学习了VB基础知识中的三种基本结构,并且学习了数组、用解析法和穷举法解决问题等算法。本节先后介绍了“什么是递归法”、“自定义函数”、以及应用自定义函数结合递归算法来解决问题实例。通过本节内容的学习可以培养学生分析和分解问题的能力。从教材的结构上看“自定义函数”和“递归算法”是独立的,可以分别讲解,但在使用时两者是相辅相成的。 【学情分析】 这节课的教学对象是高中二年级学生,已经学习了算法与程序设计VB中的一些基础知识,初步了解了算法的概念。特点是在学习循环结构的过程中,学生已经积累了一些“递归”和“穷举”的算法。但是学生对函数尤其是“自定义函数”非常陌生,而“自定义函数”和“递归法”是本册的学习重点,也是以后编程的重点。学习本节内容学生可以充分体会递归算法的思想过程,扩大原来的知识面,进一步认识程序设计的功能,进一步激发学生学习算法与程序设计的兴趣。 【教学目标】 1.知识与技能: 理解什么是递归法,会用递归法的思想分析和解决问题 理解什么是自定义函数,能应用自定义函数实现递归算法的编程 2.过程与方法 学生通过思考、探究,体验递归算法和发现问题与解决问题的步骤 3.情感态度与价值观 在建立数学模型中培养学生的抽象思维能力,培养学生多维度思考问题和解决能力。 树立多学科整合的思想意识,能够用联系的观点解决问题。 【教学重点】 理解什么是递归算法,学会用递归法的思想分析问题。 理解自定义函数的概念。 【教学难点】 用自定义函数和递归算法编写程序解决问题 【教学方法及策略】

JAVA递归算法实例小结

package com.zf.s2;// 创建一个包 import java.math.BigInteger;// 导入类 import java.util.ArrayList; import java.util.List; public class TextFactorial {// 操作计算阶乘的类 public static int simpleCircle(int num){// 简单的循环计算的阶乘int sum=1; if(num<0){// 判断传入数是否为负数 throw new IllegalArgumentException(" 必须为正整数} for(int i=1;i<=num;i++){// 循环num sum *= i;// 每循环一次进行乘法运算 } return sum;// 返回阶乘的值 } public static int recursion(int num){// 利用递归计算阶乘int sum=1; if(num < 0) throw new IllegalArgumentException(" 必须为正整数if(num==1){ return 1;// 根据条件,跳出循环 }else{ sum=num * recursion(num-1);// 运用递归计算 return sum; } } public static long addArray(int num){// 数组添加计算阶乘long[]arr=new long[21];// 创建数组arr[0]=1; int last=0; if(num>=arr.length){ throw new IllegalArgumentException(" 传入的值太大} if(num < 0) throw new IllegalArgumentException(" 必须为正整数while(last

相关主题
文本预览
相关文档 最新文档