C语言聊递归
何为递归
在C/C++、Python、Java等编程语言中都有一系列的代码块,它们可以重复被利用,需要用的时候就可以把它们调用出来,它们有一个共同的名称:函数。递归可以分解为递与归,递就是将目标穿递出去,归就是将递传递出去的目标收回,这就叫归。递归就是反复调用自己,在一个函数中调用本身。递归是一种思想,将大问题分解为小问题,解决小问题之后归并到大问题之上。递归不是一种具体实现的方法。
为什么要用递归?
众所周知,用编程语言里的顺序结构、if、while、for就可以解决大部分问题,然而在大规模问题中,这些问题有相同问题结构,,他们就是由这一层的结果来得到下一层结果,然而他们却需要相当多的for、while、if来实现,这便会让代码量剧增。在编程语言的设计人员看来,就有一种思想可以解决此类问题,那就是递归了,递归可以用少量的代码来实现程序的多次计算。
什么问题可以用递归实现?
将大问题分解为小问题,有相同的子结构(这是大前提)。我将通过一些例子来具体分析,为什么这些问题能够用递归解决。递归用到了栈,就是先进后出。
经典问题
1、斐波那契数列
当然这题可以用循环解决:
#include "stdio.h"
#define N 10
using namespace std;
int a[1000];
int main(){
int x,i=1;
scanf("%d",&x);
for(i;i<=x;i++){ //循环计算每一个f(x)的值
if(i==1||i==2)
a[i]=1;
else
a[i]=a[i-1]+a[i-2];
}
printf("%d",a[x]);
return 0;
}
经过数学总结,
有这个数学公式就可以得知当x=1或x=2时f(x)=1,当x>2时f(x)=f(x-1)+f(x-2),即f(x)等于前两项的和,然而前两项有分别等于它们前两项的和,f(x-1)+f(x-2)=f(x-3)+f(x-2)+f(x-3)+f(x-4)~~,一直计算就可以得到f(3)=f(2)+f(1)了
贴上代码:
#include "stdio.h"
int fb(int n){
if(n==1 || n==2) //当算到n==1、2时返回确切的值
return 1;
else
return fb(n-1)+fb(n-2);
}
int main(){
int x;
scanf("%d",&x); //从键盘读取x
printf("%d",fb(x));
return 0;
}
2、汉诺塔问题
汉诺塔题目的计算次数是以非常大的,若以循环写的话那可真是太糟糕了,写三、四、五个汉诺塔还行,这个一旦多起来,啧啧啧,这谁顶得住啊。如果用递归写的话那就简单多了,思路为计算一个塔盘的时候只需要将A->C,2个塔盘的时候需要在一个塔盘的基础上先将小的塔盘移到B上即A->B,再将第二个塔盘移动到C上A->C,再将B->C,这样就完成了移动,第三,第四个,等等都在前面的基础上移动,如果有四个塔盘,那就需要先移动上面三个塔盘到B上,再将B上的塔盘移动到C上。汉诺塔的题目可得花时间来消化一下哦。
如下代码:
#include<stdio.h>
void hanoit(int n, char a, char b, char c) {
if(n == 1)
printf("%c-->%c\n", a,c);
else{
hanoit(n - 1, a, c, b);
printf("%c-->%c\n",a,c);
hanoit(n - 1, b, a, c);
}
}
int main(){
int m;
scanf("%d", &m);
hanoit(m,'A','B','C');
return 0;
}
3、八皇后->N皇后问题
描述:
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
八皇后问题就是N=8的时候,这时要写八重循环来解决此问题,如果不是八,而是要从键盘中接受一个数字呢?那循环就难办了。
#include<stdio.h>
#include<cmath>
int N;
int qu[100]; //用于存放已算皇后的位置
void nQu(int k){//在k-1个皇后都摆好位置后摆第k个皇后
int i;
if(k==N){ //计算完后
for(i=0;i<N;i++)
printf("%d ",qu[i]+1); //qu[i]+1是因为数组是从0开始的
printf("\n");
return;
}
for(i=0;i<N;i++){ //尝试皇后的位置
int j;
for(j=0;j<k;j++)
if(qu[j]==i||abs(qu[j]-i)==abs(k-j))//与已摆好位置的皇后冲突,跳出
break;
if(j==k){ //不冲突,将皇后摆在i的位置
qu[k]=i;
nQu(k+1);
}
}
}
int main(){
scanf("%d",&N);
nQu(0);
return 0;
}
4、其他
阶乘、逆波兰表达式、上楼梯等问题
如何运用递归
1、找到临界条件
2、满足条件就跳出
3、有进有出(就是递进了多少层,就得返回多少层)
4、不能无限递归,不然会爆栈
注意:递归并不能优化时间复杂度,并且如果问题的规模相当的大,还有可能爆栈!
[^1]这是我以自己的理解来解释递归,如果与他人不同,望见谅!如有纰漏,望指教,谢谢!