- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
第6章 递归 【本章目录】 6.1 引言 6.2 递归程序的定义及其一般形式 6.3 递归调用的内部实现原理 6.4 递归程序的阅读 6.5 递归程序的正确性证明 6.6 递归的模拟 6.7 递归技术应用 6.1 引言 递归(Recursion) 人类解决问题“分而治之”思想; 递归是一种思考问题的方式; 递归是一种解决问题的方法; 递归是问题归约或分治法的一种。 递归和数学归纳相关。 计算机中: 递归是一种程序的形式,是一种特殊的函数调用,在函数体内调用函数自身; 递归更是一种程序设计(算法设计)的技术; 递归与栈技术的应用密切相关。 理解掌握递归技术的难点 递归的理解; 递归程序的阅读; 递归程序的验证和编写; 递归程序的运行时间及解决; 6.2 递归的定义及其一般形式 6.2.1 递归程序的定义 1. 递归定义: 在函数(过程、子程序)体中直接或间接地引用自身,则称之为递归函数。 如果一个对象全部或部分地包含它自己,或者利用自己定义自己的方式来定义或表述, 则称这个对象是递归的。 递归可以分为(多种分类方法): 直接递归—函数体中调用自身; 间接递归—本函数调用其他函数,其他函数又调用本函数。 2. 几个递归函数实例 (1)阶乘 【算法描述】 int Fact( int n ) { if(n==0) return 1; //终止条件 else return n*Fact(n-1); //递归调用 } (2) Fibonacci数 【算法描述】 int Fib(int n) { if( n==0 ) return 0; //终止条件 else if(n==1) return 1; //终止条件 else return Fib(n-1)+Fib(n-2); //递归调用 } (3)两次递归调用 【算法描述】 void P(int n) { if(n0) //终止条件:n=0 { P(n-1); //递归调用 coutn; P(n-2); //递归调用 } } (4) 间接递归 void P1(int n) { if(n0) { coutn; P2(n-1); } } 6.2.2 递归程序的一般形式 void RecFunc(参数表) { if( 递归出口条件 ) 简单操作; //递归出口(终止条件) else { 简单操作; RecFunc(参数表); //递归调用 [简单操作;] [RecFunc(参数表);] //可能有多次递归调用 [简单操作;] } } //这里给出的函数形式没有返回值,但有的递归函数是需要返回值//的,且返回值还可能参与运算 递归调用需具备的条件 (1) 原问题能逐步分解为更简单的子问题,子问题与原问题定义、求解方法相同,只是参数不同; (2) 正向递推分解子问题的过程必须有明确的结束条件,叫做递归终止条件,或递归出口。即把问题反复分解,直至产生一个可以直接求解的基本问题集合,正向递推结束。 如果没有明确的递归出口,正向分解过程将一直进行下去,对计算机程序来说,这相当于“死循环”,直至栈溢出错或系统崩溃。 (3)通过基本问题的解可以反向回归合成出原问题的解。 可见,递归求解分为两个过程:一个是正向递推分解子问题的过程;另一个是通过基本问题的解反向回归合成原问题解的过程。 6.3 递归的内部实现原理 6.3.1 一般函数调用的实现 递归调用是一种特殊的函数调用形式。 1. 函数调用要解决的问题 ①如何找到子函数(过程)的入口 我们知道每个函数都有函数名,编译成机器代码后,函数名就变为子函数第一条指令的存储地址,当调用此子函数时,比如上面的call B,CPU的程序指针指向这个地址(函数名),就找到了子函数的入口。 ②如何向子函数传递参数 许多情况下函数带有参数,比如前面给出的实例(1)求阶乘的实例(2)求Fibonacci数,执行函数调用时,需要主调函数向子函数传递这些参数(实参),这个工作是用栈来完成,即在转入子函数执行之前,把实参入栈,详情见稍后的讨论。 ③子函数执行完毕如何找到返回位置(返回地址) 子函数执行完毕,应该返回到主调函数继续执行,即返回到主调函数调用位置后面的第一条指令继续执行。 所以在转入子函数执行之前,需要把主调函数调用指令后面第一条指令的地址
文档评论(0)