一、相关知识点
1,定义:直接或间接调用自身的函数称为递归函数。
2,运用递归解题的基本思想:把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来解决,而这个最小的问题可以直接解决。
3,递归的关键在于找出递归定义和递归的终止条件。
递归定义:使问题向边界条件转化的规则。递归定义必须能使问题越来越简单。
递归终止条件:也就是所描述问题的最简单情况,它本身不再使用递归的定义。
4,递归解题的三个步骤
1)分析问题、寻找递归:找出大规模问题与小规模问题 之间的关系,这样通过递归是问题的规模逐渐变小。
2)设置边界,控制递归:找出终止条件,即算法可解的最小规模问题。
3)设计函数,确定参数:设计函数中的操作及相关参数。
二、递归的两种常见题型
(一)公式递归
例如:求n!问题
解题思路:大问题化成小问题,求n的阶乘,可以转化成求n乘以n-1的阶乘,然后n-1的阶乘等于n-1 乘以n-2的阶乘,以此类推,最后求到1的阶乘截止。此时1的阶乘也是递归的终止条件。
Include<bits/stdc++.h>
using namespacestd;
int f(int);
int main()
{
int n;
cin>>n;
cout<<f(n)<<endl;
return 0;
}
int f(int n)
{
if(n==0||n==1)return 1;//递归的终止条件。
else
return n*f(n-1);//调用自身函数
}
(一)公式递归
例如:求n!问题
解题思路:大问题化成小问题,求n的阶乘,可以转化成求n乘以n-1的阶乘,然后n-1的阶乘等于n-1 乘以n-2的阶乘,以此类推,最后求到1的阶乘截止。此时1的阶乘也是递归的终止条件。
Include<bits/stdc++.h>
using namespacestd;
int f(int);
int main()
{
int n;
cin>>n;
cout<<f(n)<<endl;
return 0;
}
int f(int n)
{
if(n==0||n==1)return 1;//递归的终止条件。
else
return n*f(n-1);//调用自身函数
}
(二)枚举递归
例1,给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。
输入数据:输入只有一行,是一个由不同的小写字母组成的字符串,已知字符长度在1-6之间。
解题思路:求n个字母的所有排列,就是求在n个位置摆放n个各不相同的字母的所有方案。如果n是固定的,比如就是7,则可以通过7重循环解决;如果n不是固定的,则需要用递归替代循环以实现枚举所有的字母组合
#include<bits/stdc++.h>
using namespace std;
const int mx=10;
char s[mx];//输入的字符串
char result[mx];//存放求出的排列
int used[mx];//表示第i个字母是否用过
int l;//字符串长度
void per(int n)
{//从排列的第n个位置开始往后排放字母
if(n==l);
{
result[l]=0;
cout<<result<<endl;
return ;
}
for(int i=0;i<l;i++)
{//在第n个位置枚举所有可能放法
if(!used[i])//如果第i个字母没用过
{
result[n]=s[i];//第n个位置放第i个字母
used[i]=1;
per(n+1);
used[i]=0;//取消第n个位置的摆法,以便下次尝试另一种摆法
}
}
}
int main()
{
cin>>s;
l=strlen(s);
me
mset(used,0,sizeof(used));
sort(s,s+l);//排序
per(0);
}
例二:半数集问题(公式递归加枚举递归)
实质:f(n)=1+(1+2+…..+n/2)f(i)//累加从1开始到n/2;
基础代码表示
int comp(int n)
{
int ans=1;
if(n>1)
{
for(int i=1;i<=n/2;i++)//枚举
ans+=comp(i);//公式
}
return ans;
}
三、学习心得
1、递归函数在解决问题时很迅速,而且减少了在主函数中写冗长繁杂的一些过程,很多难解决的问题,可以通过递归函数的方法来解决,
2、递归函数在使用过程中,一定要思维清晰,认真分析问题,弄清楚大问题小问题之间的关系,找到符合的公式,或者在公式不符合时 ,考虑用枚举递归的方法。有的问题则是需要这两种方法同时使用。
3、递归的终止条件很重要,他是递归的出口。