第 4 章 递 归 教学要求 本章重点 了解递归算法的概念与递归设计要领 掌握应用递归算法求解排序与选择、实现排列组合等典型案例

Slides:



Advertisements
Similar presentations
金融一班 王亚飞 王亚飞 王浩浩 王浩浩 吴海玥 吴海玥 我 连云港 的 家 乡 连云港 连云港,位于东经118°24′~119°48′和北纬 34°~35°07′之间,古称郁洲、海州,民国时称 连云市,建国后称新海连市,别称“港城”。东 西长129公里,南北宽约132公里,水域面积 平方公里。连云港市也是我国于1984年.
Advertisements

1.2 应用举例 ( 一 ). 复习引入 B C A 1. 什么是正弦定理? 复习引入 B C A 1. 什么是正弦定理? 在一个三角形中,各边和它所对 角的正弦的比相等,即.
不知者無罪嗎 ? 【本報台北訊】國內知名大學胡姓研究 生進口豬籠草在網路上販售,涉嫌違反 植物防疫檢疫法,胡姓研究生表示不知 道豬籠草是違禁品並當場認錯道歉 台北地檢署檢察官念他初犯,昨 天處分緩起訴,但命他繳交六萬 元緩起訴處分金作公益。 豬籠草有潛移性線蟲寄生,一旦植物感 染後,輕則枯萎凋零,重則危害農業經.
配备计算机教室、多媒体教室、图书室、卫生室、 实验室、仪器室、音体美劳器材室、心理咨询室、少先 队活动室、教师集体备课室等专用教室。实验室、仪器 室全部按照省标准配备器材,演示实验开设率达 100% 。 学校现有图书 6050 册,生均 40 册。有一个 200 米环形跑 道的运动场地。 学校基本情况.
長得像的圖形 設計者:嘉義縣興中國小 侯雪卿老師 分享者:高雄市中山國小 江民瑜老師 高雄市勝利國小 許嘉凌老師.
课例评析—— 《回乡偶书》和《渔歌子》 评课人:冯琴.
就作文本身而言,题目堪称“眉目”,是作文的“眼睛”,从某种程度上说,它是作文材料和主题的浓缩或概括。
岩石圈、板塊構造與運動 自然與生活科技 國中三年級.
幼 兒 遊 戲 訪 談 組別:第七組 班級:幼保二甲 姓名:4A0I0008劉俐音 4A0I0043吳碧娟 4A0I0059劉又甄 4A0I0060江佳霓 4A0I0061蕭靖霓 4A0I0079王毓君.
文化创新的途径.
7.4 用矩阵初等行变换 解线性方程组 主要内容: 一.矩阵的行初等变换 二.用行初等变换求逆矩阵 三.用矩阵法求线性方程组.
2009—2010学年第一学期 小学品德与社会课程教学监控情况分析 潘诗求 2010年3月
15世纪欧洲人绘制的世界地图.
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
算法设计与分析 李清勇 教授 办公室:第九教学楼北201.
计算学科的基本问题 本章首先介绍一个对问题进行抽象的典型实例——哥尼斯堡七桥问题。然后,通过“梵天塔”问题和“停机问题”分别介绍学科中的可计算问题和不可计算问题。从“梵天塔”问题再引出算法复杂性中的难解性问题、P类问题和NP类问题,证比求易算法,P=NP是否成立的问题。
第7课 新航路的开辟 第7课 新航路的开辟.
挖掘市场预期分布 建立有效投资策略 权证市场2006年中期投资策略
计算机三级考试C语言上机试题专题.
股票、债券、和保险 投资理财的话题.
确定位置 执教者:刘霞.
情緒與壓力管理─背部舒緩 指導老師:彭易璟 第六組組員:會資三乙 499A0047 謝宛霖 會資三乙 499A0019 吳汶諭
武进区三河口中学欢迎您.
电阻 新疆兵团四师76团中学.
外貌和能力哪个更重要.
从此,我不在沉默寡言 那一刻 就在这一刻 世上还有爸爸好 我 长 大 了 张绅 4 文苑芬芳
保良局黃永樹小學 數學科之數學遊蹤.
从容行走,优雅为师 江苏省梁丰高级中学 任小文
資料結構與演算法 課程教學投影片.
觀察內容: 時間 作息 觀察內容 9:30~9:40 角落分享
摄影用光 石 辉 Y O N G G U A N G P H O T O G R A P H Y.
第八章二元一次方程组 8.3实际问题与二元一次方程组.
第八章二元一次方程组 8.3实际问题与二元一次方程组 (第3课时).
导入 21世纪教育网经纬社会思品工作室制作 我们可以通过哪些媒介(途径)获知这些消息?.
专题研讨课二: 数组在解决复杂问题中的作用
第5章 函数与模块化设计 学习目的与要求: 掌握函数的定义及调用方法 理解并掌握参数的传递方法 理解函数的嵌套与递归调用
C语言程序设计 课程 第5章 数组 主讲:李祥 博士、副教授 单位:软件学院软件工程系.
由C程序结构所知,一个完整的C语言程序是由一个且只能有一个main()函数(又称主函数)和若干个其他函数组合而成的。而前面各章仅学习main()函数的编程,本章将介绍其他函数的编程,包括其他函数的定义、调用、参数传递及变量的作用域等。
選擇排序法 通訊一甲 B 楊穎穆.
第四章 函数和递归.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
第八章 函数.
書名 Java於資料結構與演算法之實習應用
Introduction to the C Programming Language
中央广播电视大学开放教育试点课程 数据结构 辅导教师 倪政林.
东北林业大学 陈宇 ACM程序设计 东北林业大学 陈宇
第11章 递归 张坤龙 天津大学计算机学院.
第0章作业: 教材P12-练习与实践 1.写出用符号’*’输出描绘汉字”大”的流程图。
For x = 0 To 9 For y = 0 To 9 z = *x + 10*y …… Next y
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
学习中苦多?乐多? ——高二(1)班主题班会.
Chap7 Recursive.
C语言复习2----函数.
请编写程序在屏幕上打印出一个“*”? printf(”*\n”); 请编写程序在屏幕上打印四行,每行一个“*”?
浙江长征职业技术学院—计算机与信息技术系—相方莉制作
第1章 绪论(二) 教学目标 理解算法的特性及评价标准 掌握算法时间复杂度和空间复杂度的分析方法 1/
第四单元:比 比的意义 浙江省诸暨市暨阳街道暨阳小学 郦 丹.
C程序设计.
資料結構與C++程式設計進階 遞迴(Recursion) 講師:林業峻 CSIE, NTU 6/ 17, 2010.
第7章 程序的结构 四、生存期与存储属性 五、extern关键字与外部连接属性 六、static关键字与内部连接属性.
第二章 类型、对象、运算符和表达式.
介入及追蹤紀錄表 編號: 姓/稱謂: 初次103年 月 日 追蹤 月 日 問題型態 (可複選) □ 1. 覺得西藥都很傷胃
第13课 东汉的兴亡.
遞迴 Recursion.
繁星推薦系統 楊曉婷 副理 教育的服務 是我們的責任.
數學科98課綱 種子教師培訓課程 (四) 教學示例
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
單元主題名: 大家都是好朋友 設計者:柯淑惠、林雨欣.
C语言基础学习 从外行到入门.
Presentation transcript:

第 4 章 递 归 教学要求 本章重点 了解递归算法的概念与递归设计要领 掌握应用递归算法求解排序与选择、实现排列组合等典型案例 第 4 章 递 归 教学要求 了解递归算法的概念与递归设计要领 掌握应用递归算法求解排序与选择、实现排列组合等典型案例 了解递归算法中的回溯过程 本章重点 递归关系与边界条件的探求与确定

4.1 递归概述 1. 递归的概念 (1) 递归(Recursion)是一个过程或函数在其定义中直接或间接调用自身的一种方法,就是利用系统堆栈,实现函数自身调用或相互调用的过程。在通往边界的过程中,都会把单步地址保存下来,再按照先进后出进行运算。 (2) 递归算法通过函数或过程调用自身将问题转化为本质相同但规模较小的子问题,是分治策略的具体体现。 (3) 递归需要有递归关系式与边界条件,递归过程有递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

2. 递归方法基本步骤 (1) 根据实际构建递归关系 (2)确定递归边界 (3)编写递归函数 (4)设计主函数调用递归函数

3. 举例说明 例4-1 用递归法计算n! 计算整数n的阶乘n!是一个典型的递归问题。使用递归方法来描述程序,十分简单且易于理解。 3. 举例说明 例4-1 用递归法计算n! 计算整数n的阶乘n!是一个典型的递归问题。使用递归方法来描述程序,十分简单且易于理解。 (1)描述递归关系 注意到,当n>1时,n!=n*(n−1)!,这就是一种递归关系。对于特定的k!,它只与k和(k−1)!有关。 (2)确定递归边界 递归边界为: n=1时,n!=1。对于任意给定的n,程序将最终求解到1!。

printf(" %d!=%ld \n",n,y); } long f(int x) { long g; if(x<=0) printf("x<=0, 输入错误!"); else if(x==1) g=1; else g=x*f(x−1); return(g);} (4)设计调用递归函数的主程序 void main() { int n;long y; scanf("%d",&n); y=f(n); // 调用函数f(n) printf(" %d!=%ld \n",n,y); }

(5) 递归调用的实现 主函数调用f(n)后即进入函数f(n)执行。 设执行本程序时输入为n=5,即求 5!。在主函数中的调用语句即为y=f(5),执行f函数,由于n=5,不等于1,故应执行g=n*f(n−1),即g=5*f(4)。该语句调用f(4),… 进行4次递归调用后,f函数参数值变为1,故不再继续递归调用而开始逐层返回主调函数。f(1)的函数返回值为1,f(2)的返回值为2*1=2,f(3)的返回值为3*2=6,f(4) 的返回值为4*6=24,最后返回值f(5)为5*24=120。

4.2 排队购票 案例提出: 一场球赛开始前,售票工作正在紧张进行中。每张球票为50元,有m+n个人排队等待购票,其中有m 个人手持50元的钞票,另外n个人手持100元的钞票。求出这m+n个人排队购票,使售票处不至出现找不开钱的局面的不同排队种数 。(约定:开始售票时售票处没有零钱,拿同样面值钞票的人对换位置为同一种排队。)

1. 递归设计要点 令f(m,n)表示有m个人手持50元的钞票,n个人手持100元的钞票时共有的排除总数。 分以下3种情况来讨论。 (1) n=0 n=0意味着排队购票的所有人手中拿的都是50元的钱币,注意到拿同样面值钞票的人对换位置为同一种排队,那么这m个人的排队总数为1,即f(m,0)=1。 (2)m<n 当m<n时,即购票的人中持50元的人数小于持100元的钞票,即使把m张50元的钞票都找出去,仍会出现找不开钱的局面,这时排队总数为0,即f(m,n)=0。

(3)其它情况 1) 第m+n个人手持100元的钞票,则在他之前的m+n-1个人中有m个人手持50元的钞票,有n-1个人手持100元的钞票,此种情况共有f(m,n-1)。 2) 第m+n个人手持50元的钞票,则在他之前的m+n-1个人中有m-1个人手持50元的钞票,有n个人手持100元的钞票,此种情况共有f(m-1,n)。 由加法原理得到f(m,n)的递归关系: f(m,n)=f(m,n-1)+f(m-1,n) 初始条件: 当m<n时,f(m,n)=0 当n=0时,f(m,n)=1

2. 购票排队的递归描述 long f(int j,int i) {long y; if(i==0) y=1; 2. 购票排队的递归描述 long f(int j,int i) {long y; if(i==0) y=1; else if(j<i) y=0; // 确定初始条件 else y=f(j-1,i)+f(j,i-1); // 实施递归 return(y); }

4.3 汉诺塔问题 案例提出: 汉诺塔(Hanoi)问题,又称河内塔问题 。 4.3 汉诺塔问题 案例提出: 汉诺塔(Hanoi)问题,又称河内塔问题 。 (1)有三根桩子A、B、C。A桩上有n个圆盘,最大的一个在底下,其余一个比一个小,依次叠上去。 (2)每次移动一块圆盘,小盘的只能叠在大盘的上面。 (3)把所有圆盘从A桩全部移到C桩上,(如图4-1)。 试求解n个圆盘A桩全部移到C桩上的移动次数,并展示n个圆盘的移动过程。

4.3.1 求移动次数 1. 递归设计要点 当n=1时,只一个盘,移动一次即完成。 4.3.1 求移动次数 1. 递归设计要点 当n=1时,只一个盘,移动一次即完成。 当n=2时,首先把小盘从A桩移到B桩;然后把大盘从A桩移到C桩;最后把小盘从B桩移到C桩,移动3次完成。 设移动n个盘的汉诺塔需g(n)次完成。分以下三个步骤: (1) 先将上面n-1个盘借助C从A移到B上,需g(n-1)次; (2) 然后将A桩上第n个盘子移到C桩上(1次); (3) 最后将B桩上的n-1个盘子借助A移到C,需g(n-1)次。 因而有递归关系:g(n)=2*g(n-1)+1 初始条件(递归出口):g(1)=1

2. 递归设计描述 // 求移动次数的递归函数 double g(int m) { double s; if(m==1) // 确定递归出口 s=1; else s=2*g(m-1)+1; // 实施递归 return s; }

4.3.2 展示移动过程 1. 递归设计要点 设递归函数hn(n,a,b,c)展示把n个盘从A桩借助B桩移到C桩的过程,函数mv(a,c)输出从a桩到c桩的过程:A-->C。 完成hn(n,a,b,c),当n=1时,即mv(a,c)。 当n>1时,分以下三步: (1) 将A上面的n-1个盘借助C移到B,即hn(n-1,a,c,b); (2) 将A桩上第n个盘子移到C桩上,即mv(a,c); (3) 将B的n-1个盘借助A移到C,即hn(n-1,b,a,c)。 主程序hn(m,1,2,3)带实参m,1,2,3调用hn(n,a,b,c),这里m为具体移动盘子的个数。

2. 递归设计描述 void mv(char x,char y) // 输出函数 { printf(" %c-->%c ",x,y); 2. 递归设计描述 void mv(char x,char y) // 输出函数 { printf(" %c-->%c ",x,y); k++; // 统计移动次数 if(k%5==0) printf(“\n”); // 输出格式 } void hn(int m,char a,char b,char c) // 递归函数 { if(m==1) mv(a,c); else { hn(m-1,a,c,b);mv(a,c);hn(m-1,b,a,c);}

4.5 快速排序与选择 1.逐项比较排序 最简单的排序是把存放在数组的n个数据逐个比较,必要时进行数据交换。 4.5 快速排序与选择 1.逐项比较排序 最简单的排序是把存放在数组的n个数据逐个比较,必要时进行数据交换。 n项逐项比较排序进行升序排序的算法描述如下: for(i=1;i<=n-1;i++) for(j=i+1;j<=n;j++) if(r[i]>r[j]) {t=r[i];r[i]=r[j];r[j]=t;} 逐项比较排序的时间复杂度为O(n^2)。

2. 快速排序 (1)快速排序思路 快速排序又称为分区交换排序,其基本思想是分治,即分而治之:在待排序的n个数据r[1,2,…,n]中任取一个数(例如r[1])作为基准,把其余n-1个数据分为两个区,小于基准的数放在左边,大于基准的数放在右边。 这样分成的两个区实际上是待排序数据的两个子列。然后对这两个子列分别重复上述分区过程,直到所有子列只有一个元素,即所有元素排到位后,输出排序结果。

(2) 分区交换描述 while(i!=j) { while(r[j]>=r[0] && j>i) // 从右至左逐个检查是否大于基准 j=j-1; if(i<j) {r[i]=r[j];i=i+1;} // 把小于基准的一个数赋给r(i) while(r[i]<=r[0] && j>i) // 从左至右逐个检查是否小于基准 i=i+1; if(i<j) {r[j]=r[i];j=j-1;} // 把大于基准的一个数赋给r(j) }

(3) 快速排序实现 (见程序c451) (4)快速排序的时间复杂度分析

3. 分区交换选择 (1) 选择问题 在一个无序序列r(1),r(2),…,r(n)中,寻找第k小元素的问题称为选择。这里第k小元素是序列按升序排列后的第k个元素。 特别地,当k=n/2时,即寻找位于n个元素中的中间元素,称为中值问题。

(2) 选择问题的分区交换设计 参照上述分区交换的快速排序算法,在待选择的n个数据r[1,2,…,n]中任取一个数(例如r[1])作为基准,把其余n-1个数据分为两个区,小于基准的数放在左边,大于基准的数放在右边,基准定位在s,则 (1) 若s=k,基准数即为所寻求的第k小元素。 (2) 若s>k,可知左边小于该基准数的个数s-1≥k,则在左边的子区继续分区。 (3) 若s<k,可知所寻求的第k小元素在右边子区,则在右边的子区继续分区。 依此(2)(3)继续,直到出现(1)结束,输出结果。

(3) 快速选择的时间复杂度分析

4.6 排列组合的实现 排列组合是组合数学的基础,从n个不同元素中任取m个,约定1<m≤n,按任意一种次序排成一列,称为排列,其排列种数记为A(n,m)。 从n个不同元素中任取m个(约定1<m<n)成一组,称为一个组合,其组合种数记为C(n,m)。 计算A(n,m)与C(n,m)只要简单进行乘运算即可,要具体展现出排列的每一列与组合的每一组,决非轻而易举。 本节应用递归设计来具体实现排列与组合。

4.6.1 实现排列A(n,m) 1. 递归设计要点 递归函数p(k)的变量k从1开始取值。当k≤m时,第k个数a(k)取i(1——n),并标志量u=0。 (1)若a(k)与其前面已取的数a(j)(j<k)比较,出现a(k)=a(j),即第k个数取i不成功,标志量u=1。 (2)若a(k)与所有前面已取的a(j)比较,没有一个相等,则第k个数取i成功,标志量保持u=0,然后判断: 1) 若k=m,即已取了m个数,输出这m个数即为一个排列,a(k)继续从i+1开始,在余下的数中取一个数。直到全部取完,则返回上一次调用p(k)处,即回溯到p(k-1),第k-1个数继续往下取值。 2) 若k<m,即还未取m个数,即在p(k)状态下调用p(k+1)继续探索下一个数,下一个数a(k+1)又从(1——n)中取数。

(3)若标志量u=1,第k个数取i不成功,则接着从i+1开始中取下一个数。若在1——n中的每一个数都取了,仍是u=1,则返回上一次调用p(k)处,即回溯到p(k-1),第k-1个数继续往下取值。 可见递归具有回溯的功能,即p(k)在取所有n个数之后,自动返回调p(k)的上一层,即回溯到p(k-1),第k-1个数继续往下取值。这也是递归能把所有排列一个不剩全部展示的原因所在。 在主程序,只要调用p(1)即可,所有排列在递归函数中输出。最后返回p(1)的a(1)取完所有数,返回排列个数s,输出排列的个数后结束。 (4)以上实现A(n,m)的递归深度为m,递归算法的时间复杂度为O(mn)。

4.6.2 实现组合C(n,m) 注意到组合与组成元素的顺序无关,约定组合中的组成元素按递增排序。因而,把以上排序程序中的约束条件作简单修改: “a[j]==a[i]” 修改为:“ a[j]>=a[i]” “a[k]==a[j]” 修改为 :“a[k]>=a[j]” 即可实现从n个不同元素中取m个(约定1<m<n)的组合C(n,m)。 这样修改实现组合的取值次数、判别次数均与实现排列相同,做了大量无效操作,效率太低。

1. 实现组合递归设计 约定组合中的组成元素递增排序,实现a 数组取值的i循环设置为: for(i=a[k-1]+1;i<=n+k-m;i++) a[k]=i; 循环起点为:a[k-1]+1,即a[k]取值要比a[k-1]大,避免了元素取相同值的判别。 循环终点为:n+k-m,即a[k]最大只能取n+k-m,为后面m-k个元素a[k+1],…,a[m]留下取值空间。 显然a[1]需从1开始取值,因而循环前设置a[0]=0; 递归函数c(k)中,a[k]取值后调用c(k+1),a[k+1]取值。 当k=m时,输出一个组合;然后a[m]继续往后取值,继续输出组合;直到a[m]取值结束,返回即回溯到前c(m-1)状态, a[m-1] 继续往后取值。 最后c(1)状态中的a[1]取值结束,即返回主程序,输出组合数s。

2. 实现可重复的组合递归设计 注意到可重复的组成元素可以相同,因而,把以上递归函数中a[i]的取值范围作简单修改: a[0]=1; for(i=a[k-1];i<=n;i++) 即后一个元素可与前面的元素取值相同,每一个元素都可取到n。这样修改可实现从n个不同元素中取m个(约定1<m<n)可重复的组合。 同时,在输出时注明“可重复”。

4.8 递归应用小结 递归与递推相比较: (1) 某些计数问题求解,可以相互替换 (2) 在处理展示与构造性案例时,不能相互替代 4.8 递归应用小结 递归与递推相比较: (1) 某些计数问题求解,可以相互替换 例“排队购票”案例求解时,我们用了递归与递推两种算法设计。 (2) 在处理展示与构造性案例时,不能相互替代 例应用递归设计展示汉诺塔移动过程,递推却难以实现。 (3) 递归的求解效率低于递推 递归数据要不断的进栈出栈,且存在大量的重复计算。递推免除了数据进出栈的过程,直接从边界出发,逐步推出函数值,避免了重复计算。因而递推效率远远高于递归。

第4章作业 第4章上机 习题4: 1, 2, 3, 4, 5, 6 (1) 上机通过本章汉诺塔问题、快速排序与选择、排列组合的实现等案例; 习题4: 1, 2, 3, 4, 5, 6 第4章上机 (1) 上机通过本章汉诺塔问题、快速排序与选择、排列组合的实现等案例; (2) 上机通过例4-3,比较递归与递推求整数s的划分数的效率 。 (3) 分组讨论并上机通过旋转数阵、整数的拆分等案例。

欢迎大家提出教学建议 返回