若一个对象部分地包含它自己, 或用它自己给自己定义, 则称这个对象是递归的;若一个过程直接地或间接地调用自己, 则称这个过程是递归的过程。
一个直接调用自己或通过一系列调用语句间接调用自己的函数。
数学函数:阶乘函数、2阶Fibonacci数列
数据结构:二叉树、广义表
八皇后、hanoi塔问题
将规模较大的原问题分解为一个或多个规模更小的与原问题类似的子问题-递归步骤(递归表达式)
确定一个或多个无须分解可直接求解的子问题-终止条件
建立递归工作栈
调用时
为调用者生成一个活动记录
压入运行时刻栈
程序控制权转交给被调函数
返回时
被调函数执行完毕,运行时刻栈顶的活动结构退栈,
根据退栈的活动结构中保存的返回地址将程序控制权交给调用者继续执行
代码
int fact(int n)
{ if (n= =0)
{ s=1; return 1;}
else
{ s=n*fact(n-1); //<——ReLoc2
return s;
}
}
void main()
{ int N= fact(5);}//<——ReLoc1
从图中可看到主函数调用fact(5)的过程,在函数过程体中,else语句以参数4,3,2,1,0,即、fact(4)、fact(3)、fact(2)、fact(1、fact(0)。即,fact(5)为主函数调用,其它则为在fact函数内调用。每一次递归调用并未立即得到结果,而是进一步向深度递归调用,直到n=1或n=0时,函数fact结果为1,然后再一一返回计算,最终得到结果。
空间效率 : O(n) 与递归树的深度成正比
空间效率 : O(2n) 与递归树的结点数成正比
优点:结构清晰,程序易读
缺点:每次调用要生成工作记录,保存状
态信息,入栈;返回时要出栈,恢复状态
信息。时间开销大。
传说在创世纪时,在一个叫Brahma的寺庙里,有三个柱子,其中一柱上有64个盘子从小到大依次叠放,僧侣的工作是将这64个盘子从一根柱子移到另一个柱子上。
移动时的规则:
当工作做完之后,就标志着世界永远和平。
设三根柱子分别为 x,y, z , 盘子在x柱上,要移到z柱上。
1、当n=1时,盘子直接从 x 柱移到 z 柱上;
2、当n>1时, 则
void Hanoi(int n,char x,char y,char z)
{ //将n个编号从上到下为1…n 的盘子从 x 柱,借助y柱移到z柱
if(n ==1)
move(x,1,z); //将编号为1的盘子从x柱移到z柱
else
{ //将n-1个编号从上到下为1…n-1的盘子从x柱,借助y柱移到z柱
Hanoi(n-1,x,z,y);
move(x,n,z);//将编号为 n 的盘子从 x 柱移到 z 柱
//将n-1个编号从上到下为1…n-1的盘子从y柱,借助x柱移到z柱
Hanoi(n-1,y,x,z);
}
} //Hanoi
#include
int sum=0;//全局变量,记录第几次搬
void hanoi(int n,char x,char y,char z)//递归函数,将编号为n的的盘子借助y柱子,从x柱子到z柱子
{
if(n==1)//如果是1,就直接搬
printf("第%d轮,将%d号盘子从%c号柱子到%c号柱子\n",++sum,n,x,z);
else//不然的话,就要先把上面n-1个盘子从x搬到y,再将n从x搬到z
{
hanoi(n-1,x,z,y);//把上面n-1个盘子从x搬到y
printf("第%d轮,将%d号盘子从%c号柱子到%c号柱子\n",++sum,n,x,z);//再将n号盘子从x搬到z
hanoi(n-1,y,x,z);//剩下的盘子在y柱子上,就要借助x柱子,从y到z柱子,继续递归
}
}
int main()
{
char x='X',y='Y',z='Z';
int n=5;//定义有5个盘子
hanoi(n,x,y,z);
}
求:1/1!-1/3!+1/5!-1/7!+…+(-1)n+1/(2n-1)!
#include
using namespace std;
int main( )
{int i,n,j,sign=1;
float s,t=1;
cin>>n;
s=1;
for(i=2;i<=n;i=i+1)
{t=1; /*求阶乘*/
for(j=1;j<=2*i-1;j=j+1)
t=t*j;
sign =1; /*求(-1)n+1*/
for(j=1;j<=i+1;j=j+1)
sign = sign *(-1);
s=s+ sign/t;
}
cout<<"Sum="<<s;
}
如:28的因子为1、2、4、7,14,而28=1+2+4+7+14。因此28是“完数”。
编算法找出1000之内的所有完数,并按下面格式输出其因子:28 it’s factors are 1,2,4,7,14。
#include
using namespace std;
int main()
{
int a[20];
int s,k,n=1000; //k为数组下标,s为累加和。
int i,j; //循环变量
for(i=2;i<n;i++)
{
//判断 i 是否为完数。
a[0]=1;k=1;s=1;
for(j=2;j<i;j++)
{
if(i%j==0)
{s=s+j;a[k]=j;k=k+1;}
}
if(s==i)
{cout<<s<<" it is a factors are "; //输出完数
for(j=0;j<k;j++)
{cout<<" "<<a[j]; //输出完数因子
}
cout<<endl;}
}
return 0;
}
#include
using namespace std;
int main()
{
int a[100][100];//存储打印的规则图形的矩阵,下三角矩阵
int k = 1,n;//打印的数据,1-n
cin>>n;
//赋值
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n+1-i; ++j)
{
a[i-1+j][j] = k;
k++;
}
}
//打印
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= i; ++j)
{
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
#include
using namespace std;
//循环实现
int main()
{
int n,sum=0;
cin>>n;
for(int i=1;i<=n;i++)
{
sum+=i;
}
cout<<sum;
return 0;
}
//递归实现
int sum(int n) //定义sum()函数;
{
if(1 == n)
return 1;
else
return n+sum(n-1);
}
int main(void)
{
int n;
cin>>n;
cout<<sum(n); //sum(x)是调用sum()函数;
return 0;
}
对于一个正整数n的分划就是把n写成一系列正整数之和的表达式。例如,对于正整数n=6,它可以分划为:
6
5+1
4+2, 4+1+1
3+3, 3+2+1, 3+1+1+1
2+2+2, 2+2+1+1, 2+1+1+1+1
1+1+1+1+1+1
根据例子发现“包括第一行以后的数据不超过6,包括第二行的数据不超过5,……,第六行的数据不超过1”。
因此,定义一个函数f(n,m),表示整数n的“任何被加数都不超过m”的分划的数目,n的所有分划的数目P(n) =f(n,n)。
模型建立:
一般地f(n.m)有以下递归关系:
1)f(n,n)=1+f(n,n-1) (m=n)
f(n,n-1)表示n的所有其他分划,即最大被加数m<=n-1的划分。
2)f(n,m)=f(n,m-1)+f(n-m,m) (m f(n,m-1)表示被加数中不包含m的分划的数目; f(n-m,m)表示被加数中包含(注意不是小于)m的分划的数目。 递归的停止条件: 1)f(n,1)=1,表示当最大的被加数是1时,该整数n只有一种分划,即n个1相加; 打印图像代码 6、任给十进制的正整数,请从低位到高位逐位输出各位数字。 }
2)f(1,m)=1,表示整数n=1只有一个分划,不管最大被加数的上限m是多大。#include
#include
#include
7、任给十进制的正整数,请从高位到低位逐位输出各位数字。
#include
8、找出n个自然数(1,2,3,…,n)中r个数的组合。
#include