递归简介
递归算法是一种通过自身调用自身或者间接调用自身来达到解决问题的算法;
基本思想是把一个要求解的问题的划分成一个或者多个规模较小的子问题,这些子问题与原问题保持同一类型;
特性:
- 规模为n的问题可以转化为规模较小的问题,前一次的输出为后一次的输入
- 递归必须是次数有限的,且每一次递归调用后,越来越近似于限制条件
- 必须有结束递归的条件,n=1是得解
递归优缺:
进行重复计算时算法更直观便于理解,易验证
缺:
递归不断地进行函数调用,运行效率低,占用空间较多,此时使用循环效率会大大提高
递归模板:
//递归模板
return_type recursion_func(return_type yret, int n )
{
if(n is ok ) return yret; //限制条件
// do(yret) 为处理方法,n-1 表示问题更近一步
return recursion_func(do(yret),n-1);
}
递归样例
1.求m的n次方问题
//1.计算2的阶乘
long mult_num(long all,int n){
if(0>=n) return all;
return mult_num(all*2,n-1); //2的阶乘最终变成乘法:all*2
}
long mult_num_Test(int n){
printf("num [%d]=[%u]\n",n,mult_num(1,n));
return 0;
}
//2.计算m的n级阶乘
long mult_num(long all,int m,int n){
if(0>=n) return all;
return mult_num(all*m,m,n-1);//2的阶乘最终变成乘法:all*m
}
long mult_num_Test(int m,int n){
printf("num [%d]=[%u]\n",n,mult_num(1,m,n));
return 0;
}
2.求阶乘问题
//求n的阶乘
long mult_num(long all,int n){
if(1>=n) return all; //终止条件
return mult_num(all*n,n-1); //子问题的解法:
}
long mult_num_Test(int n){
printf("num [%d]=[%u]\n",n,mult_num(1,n));
return 0;
}
3.斐波那契数列fibonacci
第n个数等于(n-1)+ (n-2)
//斐波那契数列
int fibonacci_num(int n){
int m=n-1;
if(1==n) return 0;
if(2==n) return 1;
return fibonacci_num(n-1) + fibonacci_num(n-2);
}
int fibonacci_num_Test(int n){
printf("[%d]\t{",n);
while(n>=1)
{
printf("%d ",fibonacci_num(n--));
}
printf("}\n");
return 0;
}
4.全排列问题
输入n个字符,输出可能的排列方式
int char_exchange(char* a,char *b){
char c=*a;
*a=*b;
*b=c;
return 0;
}
char* fibonacci_num( char* pstr,char * pchar ,int deep){
// printf("===%s===\n",pchar);
if('\0' == *(pchar+1)){
//这里使用的打印,也可以使用链表来存储
printf("[%s] \n",pstr);
return pstr;
}else{
// printf("####### [%s] [%s] [%d]###########\n",pstr,pchar,deep);
char *pold=pchar;//保存状态
pchar=pchar+1; //准备进入下一层递归
deep++; //深度统计-方便调试
/* 计算主体:打乱当前排序,再分别进行组合 */
char *pnew=pold;
while('\0' != *pnew){
char_exchange(pold,pnew);
fibonacci_num(pstr,pchar,deep);
pnew++;
}
//要恢复顺序,确保返回上一轮的操作时,字符串顺序不变
pnew=pchar;
while('\0' != *pnew)
{
char_exchange(pnew,pnew-1);
pnew++;
}
return pstr;
}
}
//测试
int fibonacci_num_Test(){
char str[32]="ABCD";
printf("-----[%s]------:\n",str);
fibonacci_num(str,str+0,0);
return 0;
}
5.八皇后问题
从验证开始,先写验证算法,用以为数字的下标表示X轴,数组的值表示x轴,则数组应满足以下条件:
1 | 数组不能有空值,且范围在[1,8] | 不在同一行 |
2 | 数组的值,不能相同 | 不在同一列 |
3 | 数组的值与下标的差,生成的数组 | 不在斜对角 |
4 | 数组的值与下标的和,生产的数组 | 不在斜对角 |
#define QNUN 8
//检查有没有重复的数字
int find_same_num(int *pnum)
{
for(int i=0;i<QNUN;i++){
for(int j=i+1;j<QNUN;j++){
if(pnum[i] == pnum[j]){
printf("index=[%d] value[%d]\n",i,pnum[i]);
return 1;
}
}
}
return 0;
}
int check_8queen(int *pnum){
int sum[QNUN];
int diff[QNUN];
/*1.在同一行*/
for(int i=0;i<QNUN;i++){
if(!(pnum[i] >= 0 || pnum[i] < QNUN ))
return 1;
}
/*2.在同一列 */
if(0 != find_same_num(pnum))
return 2;
/*3.比较 差集 */
printf("## diff : \n");
for(int i=0;i<8;i++){
diff[i] = i - pnum[i];
printf("%d - %d = [%d]\n",i,pnum[i],diff[i]);
}
if(0 != find_same_num(diff))
return 3;
/*4.比较 和集 */
printf("## sum :\n ");
for(int i=0;i<8;i++){
sum[i] = i + pnum[i];
printf("%d + %d = [%d]\n",i,pnum[i],sum[i]);
}
if(0 != find_same_num(sum))
return 4;
return 0;
}
这样八皇后问题就变成了,0-7 八个数字的随机组合(全排列问题),然后验证每一组是否满足。这是穷尽法。穷举法
那么,如果使用递归来处理呢?
6.汉诺塔问题hannoi