第六章 递归算法

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

6.7 设计举例
6.7.1 一般递归函数设计举例 例1: 设计一个输出如下形式数值的递归函数。 : 设计一个输出如下形式数值的递归函数。 n n n ... n ...... 3 3 3 2 2 1
递归函数设计如下 : public static void display(int n){ for(int i = 1; i <= n; i ++){ System.out.print(" } System.out.println(); " + n);
6.2 递归算法的执行过程
例1:阶乘的递归算法 :
public static long fact(int n) throws Exception{ int x; long y; if(n < 0){ throw new Exception("参数错!"); 参数错! 参数错 } if(n == 0) return 1; else{ x = n - 1; y = fact(x); return n * y; } }
例 :汉诺塔问题的递归求解过程
A B C A B C
1 2 3 4 (a) 4 (b) 1 2 3
A
B
C
A
B
C
1 1 2 3 (c) 4 (d) 2 3 4
6.4 递归过程和运行时栈
递归函数的执行过程具有三个特点: 递归函数的执行过程具有三个特点: (1)函数名相同; )函数名相同; (2)不断地自调用; )不断地自调用; (3)最后被调用的函数要最先被返回。 )最后被调用的函数要最先被返回。 系统用于保存递归函数调用信息的堆栈称作运行时栈。 系统用于保存递归函数调用信息的堆栈称作运行时栈。 运行时栈 每一层递归调用所需保存的信息构成运行时栈的一个工作 每一层递归调用所需保存的信息构成运行时栈的一个工作 记录 栈顶的工作记录保存的是当前调用函数的信息, 栈顶的工作记录保存的是当前调用函数的信息,所以栈顶 的工作记录也称为活动记录 活动记录。 的工作记录也称为活动记录。
递归调用执行过程: 递归调用执行过程:
6.3 递归算法的设计方法
适宜于用递归算法求解的问题的充分必要条件是: 适宜于用递归算法求解的问题的充分必要条件是: (1)问题具有某种可借用的类同自身的子问题描述的性质 ) (2)某一有限步的子问题(也称作本原问题)有直接的解 )某一有限步的子问题(也称作本原问题) 存在。 存在。 当一个问题存在上述两个基本要素时, 当一个问题存在上述两个基本要素时,设计该问题的递归 算法的方法是: 算法的方法是: (1)把对原问题的求解表示成对子问题求解的形式。 )把对原问题的求解表示成对子问题求解的形式。 (2)设计递归出口。 )设计递归出口。
当 n = 0时 当 n = 1时 当 n > 1时
6−4
按照上式,求第 项斐波那契数列的递归函数如下 项斐波那契数列的递归函数如下: 按照上式,求第n项斐波那契数列的递归函数如下:
public static long fib(int n){ if(n == 0 || n == 1) return n; else return fib(n - 1) + fib(n - 2); } //递归出口 递归出口 //递归调用 递归调用
设计一个计算3!得主函数如下 用来说明递归算法的 设计一个计算 !得主函数如下,用来说明递归算法的 执行过程: 执行过程:
public static void main(String[] args){ long fn; try{ fn = fact(3); System.out.println("fn = " + fn); } catch(Exception e){ System.out.println(e.getMessage()); } }
if(n > 0) display(n - 1);
//递归 递归
//n<=0为递归出口,递归出口为空语句 为递归出口, 为递归出口 }
例2:设计求解委员会问题 :
A B C D E
C D C E A B A C A D A E
B
C
B
D
B
E
D
E
B C D E
A A A A
B C D E
B
B
C
B
D
B
E
阶乘递归函数运行时栈的变化过程: 阶乘递归函数运行时栈的变化过程:
6.5 递归算法的效率分析
我们以斐波那契数列递归函数的执行效率为例来讨论 递归算法的执行效率问题。 递归算法的执行效率问题。 斐波那契数列Fib(n)的递推定义是: 斐波那契数列 的递推定义是: 的递推定义是
0 Fib ( n ) = 1 Fib ( n − 1) + Fib ( n − 2 )
测试主函数设计如下: 测试主函数设计如下:
public static void main(String[] args){ int[] a = {1, 3, 4, 5, 17, 18, 31, 33}; int x = 17; int bn; bn = bSearch(a, x, 0, 7); if(bn == -1) System.out.println("x不在数组 中"); 不在数组a中 不在数组 else System.out.println("x在数组 中,下标为 + bn); 在数组a中 下标为" 在数组 }
fib(5)的递归调用树 的递归调用树
Fib(5)
Fib(4)
Fib(3)
Fib(3)
Fib(2)
Fib(2)
Fib(1)
Fib(2)
Fib(1)
Fib(1)
Fib(0)
Fib(1)
Fib(0)
Fib(1)
Fib(0)
6.6 递归算法到非递归算法的转换
一般来说,如下两种情况的递归算法可转化为非递归算法: 一般来说,如下两种情况的递归算法可转化为非递归算法: (1)存在不借助堆栈的循环结构的非递归算法,如阶乘计算 )存在不借助堆栈的循环结构的非递归算法, 问题、斐波那契数列的计算问题、 问题、斐波那契数列的计算问题、折半查找问题等 (2)存在借助堆栈的循环结构的非递归算法。所有递归算法 )存在借助堆栈的循环结构的非递归算法。 都可以借助堆栈转换成循环结构的非递归算法。 都可以借助堆栈转换成循环结构的非递归算法
递归调用执行过程: 递归调用执行过程:
例2:折半查找递归算法 折半查找递归算法
public static int bSearch(int[] a, int x, int low, int high){ int mid; if(low > high) return -1; mid = (low + high) / 2; if(x == a[mid]) return mid; else if(x < a[mid]) return bSearch(a, x, low, mid - 1); else return bSearch(a, x, mid + 1, high); } //在下半区查找 在下半区查找 //在上半区查找 在上半区查找 //查找成功 查找成功 //查找不成功 查找不成功
+
C D E
C
D
C
E
DБайду номын сангаас
E
6.72 回溯法及设计举例 回溯法的基本思想是:对一个包括有很多结点, 回溯法的基本思想是:对一个包括有很多结点,每个 的基本思想是 结点有若干个搜索分支的问题, 结点有若干个搜索分支的问题,把原问题分解为对若 干个子问题求解的算法。当搜索到某个结点、 干个子问题求解的算法。当搜索到某个结点、发现无 法再继续搜索下去时,就让搜索过程回溯(即退回) 法再继续搜索下去时,就让搜索过程回溯(即退回) 到该结点的前一结点,继续搜索这个结点的其他尚未 到该结点的前一结点, 搜索过的分支; 搜索过的分支;如果发现这个结点也无法再继续搜索 下去时,就让搜索过程回溯到这个结点的前一结点继 下去时, 续这样的搜索过程; 续这样的搜索过程;这样的搜索过程一直进行到搜索 到问题的解或搜索完了全部可搜索分支没有解存在为 止。
例:求解迷宫问题
迷宫问题的搜索过程: 迷宫问题的搜索过程:
路口 1 2 3 4(死 路 ) 3(死 路 ) 2 5(死 路 ) 2 6 动作 向前 向左 向右 回溯 回溯 向前 回溯 向右 向左 结果 进入2 进入3 进入4 进入3 进入2 进入5 进入2 进入6 进入7
第6章 递归算法 章
6.1 递归的概念 6.2 递归算法的执行过 6.3 递归算法的设计方法 6.4 递归过程和运行时栈 6.5 递归算法的效率分析 6.6 递归算法到非递归算法的转换 6.7 设计举例
本章主要知识点: 本章主要知识点: ● 递归的概念 ● 递归算法的设计方法 ● 递归算法的执行过程 ● 递归算法的效率
6.1 递归的概念
若一个算法直接地或间接地调用自己本身, 若一个算法直接地或间接地调用自己本身,则称 这个算法是递归算法。 这个算法是递归算法。 递归算法 1.问题的定义是递归的 问题的定义是递归的 例如: 例如:阶乘函数的定义 1 n= n*(n-1) 当n>0时 时 当n=0时 时
2. 问题的解法存在自调用 例如: 例如:折半查找算法
相关文档
最新文档