第五章、递归
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
⑨
Fib(4)
⑤
⑧ຫໍສະໝຸດ Baidu
Fib(3)
③
④
Fib(2)
⑥
⑦
Fib(2)
Fib(1)
Fib(1)
Fib(0)
①
②
Fib(1)
Fib(0)
1. 采用系统提供的递归工作栈:
计算机中对子程序的调用(即C/C++中的函数调用)通常是 通过程序中断方式实现的
采用程序中断方式
在调用子程序前,需要保护现场(即保护调用程序的 局部变量值、实在参数值),和保护断点(即返回地址), 在调用子程序后,需要恢复现场和恢复断点。
}
void main()
{
long n; cout<<"Enter number :"; cin>>n;
for(int i=0;i<=n;i++)
cout<< "Fib(" << i << ")=" << Fib(i) <<endl;
}
说明:
main()调用Fib(),称作外部调用
Fib()自己调用自己称作内部调用
非终结问题经过有限次递归,最终可分解为终结问题。
常见使用递归的地方:
定义是递归的: 数据结构是递增归的: 问题是递归的
递归过程的计算机实现
递归过程:
一个过程在进行中又涉及自身,称此过程为递归过程 此处过程有两种含义:广义的和狭义的
广义的递归过程:描述某个事件的进行特性。 狭义的递归过程(递归算法):特指计算机中通过使用系
while(n>1) { w->n=n;
w->tag=1; s.Push(*w); n- -; } sum+=n; while(! s.IsEmpty()) { *w=s.GetTop();
s.Pop(); if(w->tag==1) { w->tag=2; s.Push(*w); n=w->n-2; break; }
fmffmfafafaaacaccaccttcitti(tn(t(n(2(4(24(13()3))))) fact(1) fact(2)
void main()
段则是共用的
fact(3)
{ cout<< fact(4); }
ffaacctt((44))
main() fact(4)
fact(3)
fact(2) fact(1)
递归
《数据结构》第五章
本章主要内容
递归概念 递归过程的计算机实现 递归过程不同实现方法 可利用递归方法实现的
算法 分治法问题举例 回溯法问题举例 广义表
递归概念
递归的概念:
若一个对象部分地包含自己,则称这个对象是递增归的。
递归问题的特点:
该问题能分解为两类子问题: 非终结问题:需进一步递归的子问题。 终结问题:不需进一步递归就可求解的子问题。 终结问题,亦称为递归终止条件。
struct Node
//用户栈结点的类定义
{ long n; int tag;
Node(long m=0,int t=0):n(m),tag(t){ }
//构造函数,用于将整型数转换为Node型
};
void main()
{
long n;
cout<<"Enter number :";
cin>>n;
for(int i=0;i<=n;i++)
在上层运算即将转入下层运算前,将上层运算的中间结 果入栈。
在下层运算结束退回上层运算时,将上层运算的中间结 果出栈
使用用户定义栈求裴波那契数列: (黄色为修改部分)
#include<iostream.h>
#include "… …\sequence_stack.h"
long Fibonacci(long n); //求裴波那契数列函数说明
保护现场和断点、恢复现场和断点都是通过系统提供 栈来实现的。
在调用子程序前,系统自动生成一个包含现场和断点 数据的工作记录,并将工作记录压入系统栈保护起来
在返回调用程序前,系统自动从系统栈中将工作记录 弹出
使用系统提供的栈实现的递归过程,实质上是子程序嵌套 调用的特例,即函数嵌套调用自己。常称作递归算法。
mmaaiinn(())
fa2c4t(4) 4* f4a*c6t(3) 3* 3fa*c2t(2) 2* f2a*c1t(1)
【例】用系统工作栈求裴波那契数列:
#include<iostream.h>
long Fib(long n)
{
if ( n<=1) return n;
return Fib( n-1 )+Fib( n-2 );
2. 采用用户自定义栈实现递归过程:
递归过程也可通过引入用户自定义的栈模拟系统提供的 栈操作来加以实现。
这种实现不涉及程序的自我调用(即不涉及程序的中断调 用)。也就不涉及断点保护问题。
数据的入栈及出栈操作不是由系统自动完成,而是由用 户通过编码加以实现,通常称为非递归算法。
用户栈中保存的是不同层递归调用树操作产生的中间结 果数据。
cout<<"Fibonacci("<<i<<")="<<Fibonacci(i)<<endl;
}
(未完,转下页)
long Fibonacci(long n) //求裴波那契数列函数定义 {
Stack<Node> s(50); //用户定义栈 Node* w=new Node; long sum=0; do{
统工作栈实现子程序的自我调用。
递归过程的计算机实现,可有三种方法:
利用系统提供的递归工作栈实现 利用用户自定义的栈实现 用叠代方法实现
用递归调用树描述递归过程:
【例】裴波那契数列的递推公式:
Fib(n)=
n
当n=0或n=1时
Fib(n-1)+Fib(n-2) 当n>=2时
计算n==4时裴波那契数列的递归调用树:
其特点是:
不同层次的递归调用,调用的是都是同一段代码(即递 归函数体自身)
但函数每递归调用自己一次,都必须在系统栈中重新分 配一个内存空间(即所谓工作记录),以便存放本层使用 的局部变量和实在参数
显然,不同层次的递归调用,它们的局部变量的变量名 虽然相同,但是作为不同的工作记录的组成部份,存放 在系统栈的不同地方(即内存的不同地方),它们之间是 彼此独立的。
不同层次的局部变量之间可通过实在参数与形式参数进 行数据传递。
#include<iostream.h>
long fact(long n) { if(n<=1)
return 1; else return n*fact(n-1);}
函数递归调用, 各次调用的数据 存放在栈的不同 空间,彼此相互 独立,函数代码
Fib(4)
⑤
⑧ຫໍສະໝຸດ Baidu
Fib(3)
③
④
Fib(2)
⑥
⑦
Fib(2)
Fib(1)
Fib(1)
Fib(0)
①
②
Fib(1)
Fib(0)
1. 采用系统提供的递归工作栈:
计算机中对子程序的调用(即C/C++中的函数调用)通常是 通过程序中断方式实现的
采用程序中断方式
在调用子程序前,需要保护现场(即保护调用程序的 局部变量值、实在参数值),和保护断点(即返回地址), 在调用子程序后,需要恢复现场和恢复断点。
}
void main()
{
long n; cout<<"Enter number :"; cin>>n;
for(int i=0;i<=n;i++)
cout<< "Fib(" << i << ")=" << Fib(i) <<endl;
}
说明:
main()调用Fib(),称作外部调用
Fib()自己调用自己称作内部调用
非终结问题经过有限次递归,最终可分解为终结问题。
常见使用递归的地方:
定义是递归的: 数据结构是递增归的: 问题是递归的
递归过程的计算机实现
递归过程:
一个过程在进行中又涉及自身,称此过程为递归过程 此处过程有两种含义:广义的和狭义的
广义的递归过程:描述某个事件的进行特性。 狭义的递归过程(递归算法):特指计算机中通过使用系
while(n>1) { w->n=n;
w->tag=1; s.Push(*w); n- -; } sum+=n; while(! s.IsEmpty()) { *w=s.GetTop();
s.Pop(); if(w->tag==1) { w->tag=2; s.Push(*w); n=w->n-2; break; }
fmffmfafafaaacaccaccttcitti(tn(t(n(2(4(24(13()3))))) fact(1) fact(2)
void main()
段则是共用的
fact(3)
{ cout<< fact(4); }
ffaacctt((44))
main() fact(4)
fact(3)
fact(2) fact(1)
递归
《数据结构》第五章
本章主要内容
递归概念 递归过程的计算机实现 递归过程不同实现方法 可利用递归方法实现的
算法 分治法问题举例 回溯法问题举例 广义表
递归概念
递归的概念:
若一个对象部分地包含自己,则称这个对象是递增归的。
递归问题的特点:
该问题能分解为两类子问题: 非终结问题:需进一步递归的子问题。 终结问题:不需进一步递归就可求解的子问题。 终结问题,亦称为递归终止条件。
struct Node
//用户栈结点的类定义
{ long n; int tag;
Node(long m=0,int t=0):n(m),tag(t){ }
//构造函数,用于将整型数转换为Node型
};
void main()
{
long n;
cout<<"Enter number :";
cin>>n;
for(int i=0;i<=n;i++)
在上层运算即将转入下层运算前,将上层运算的中间结 果入栈。
在下层运算结束退回上层运算时,将上层运算的中间结 果出栈
使用用户定义栈求裴波那契数列: (黄色为修改部分)
#include<iostream.h>
#include "… …\sequence_stack.h"
long Fibonacci(long n); //求裴波那契数列函数说明
保护现场和断点、恢复现场和断点都是通过系统提供 栈来实现的。
在调用子程序前,系统自动生成一个包含现场和断点 数据的工作记录,并将工作记录压入系统栈保护起来
在返回调用程序前,系统自动从系统栈中将工作记录 弹出
使用系统提供的栈实现的递归过程,实质上是子程序嵌套 调用的特例,即函数嵌套调用自己。常称作递归算法。
mmaaiinn(())
fa2c4t(4) 4* f4a*c6t(3) 3* 3fa*c2t(2) 2* f2a*c1t(1)
【例】用系统工作栈求裴波那契数列:
#include<iostream.h>
long Fib(long n)
{
if ( n<=1) return n;
return Fib( n-1 )+Fib( n-2 );
2. 采用用户自定义栈实现递归过程:
递归过程也可通过引入用户自定义的栈模拟系统提供的 栈操作来加以实现。
这种实现不涉及程序的自我调用(即不涉及程序的中断调 用)。也就不涉及断点保护问题。
数据的入栈及出栈操作不是由系统自动完成,而是由用 户通过编码加以实现,通常称为非递归算法。
用户栈中保存的是不同层递归调用树操作产生的中间结 果数据。
cout<<"Fibonacci("<<i<<")="<<Fibonacci(i)<<endl;
}
(未完,转下页)
long Fibonacci(long n) //求裴波那契数列函数定义 {
Stack<Node> s(50); //用户定义栈 Node* w=new Node; long sum=0; do{
统工作栈实现子程序的自我调用。
递归过程的计算机实现,可有三种方法:
利用系统提供的递归工作栈实现 利用用户自定义的栈实现 用叠代方法实现
用递归调用树描述递归过程:
【例】裴波那契数列的递推公式:
Fib(n)=
n
当n=0或n=1时
Fib(n-1)+Fib(n-2) 当n>=2时
计算n==4时裴波那契数列的递归调用树:
其特点是:
不同层次的递归调用,调用的是都是同一段代码(即递 归函数体自身)
但函数每递归调用自己一次,都必须在系统栈中重新分 配一个内存空间(即所谓工作记录),以便存放本层使用 的局部变量和实在参数
显然,不同层次的递归调用,它们的局部变量的变量名 虽然相同,但是作为不同的工作记录的组成部份,存放 在系统栈的不同地方(即内存的不同地方),它们之间是 彼此独立的。
不同层次的局部变量之间可通过实在参数与形式参数进 行数据传递。
#include<iostream.h>
long fact(long n) { if(n<=1)
return 1; else return n*fact(n-1);}
函数递归调用, 各次调用的数据 存放在栈的不同 空间,彼此相互 独立,函数代码