递归调用的定义是:在调用一个函数的过程中又要直接或间接调用这个函数本身。
基本形式如:
int f()
{
......
x = f();
......
}
我认为递归就像是一个走楼梯的过程,每两层楼梯之间都存在一种同样的关系,
我们只知道怎么往上走,却不知道怎么往下走,
而且除了这种关系,我们只知道最底层楼梯的数据。
所以我们为了走到最底层,不断地假设我们如果在下一层,会怎么往上走,这就是函数调用自身的过程
从 f 函数中再调用 f 函数,直到假设到最后一层
获取到数据之后,就开始上楼梯,利用数据得到最里层函数的值,再推出再外层......直到得到最外层也就是最开始调用自身的那层的值。
至于什么时候该停止,就可以用if语句来控制。
如:我们要求n的阶乘,就可以用这种递归的思想:
我们要求的是最上层的n!
知道了1!= 1,这是最底层的已知数据,
还知道一种关系:本层n!是下一层(n - 1)!再乘n,符合上述走楼梯的条件,可以写出
#include <stdio.h>
#include <stdlib.h>
int main()
{
int jc(int n);
int n;
scanf("%d", &n);
printf("%d", jc(n));
return 0;
}
int jc(int n)
{
int c;
if(n == 1)
c = 1; //走到最底层时,结果为1
else
c = jc(n - 1)*n; //调用自身:本层 = 下层 * n
return c;
}
这是简单的问题,其实如果不用递归,从n = 1开始正着解其实也可以很容易解出n的结果
而且比起正向思维的解法,递归消耗的时间要更长,正着解只是一个直接的过程,而递归却需要逐层调用到n = 1的情况,再从n = 1,逐层解回来
所以对于一般问题来说,递归的效率通常是比较低的,一般没有必要使用。
但是,对于有些问题,正向思维是无法解决的,或者说解决起来很麻烦,而递归,则可以简化思维。
比如汉诺塔问题:
Description
汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
最后将所有圆盘移动到C柱上。
Input
一个正整数n
Output
输出移动圆盘的最少次数的移动方法的每一步。每次移动输出一行,如从A到B,就输出A->B
这个问题中,如果n比较大,能够正着移出来,都十分困难,更不用说是最少的步骤了
但是如果按照递归的思想的话,问题就会简单很多
我们知道,最后一步是:将上面n - 1个盘子从a移动到b,将最大的盘子从a移到c,最后将n-1个盘子从b移到c
要将n-1个盘子从a移动到b,就可以继续上面的思想,直到最后只剩n - 1 为1时只移动最后那一个即可
整个过程中,只有abc三个柱子的功能变化了
写出如下程序:
#include <stdio.h>
#include <stdlib.h>
int main()
{
void hanoi(int n, char one, char two, char three);
int m;
scanf("%d", &m);
hanoi(m, 'A', 'B', 'C');
return 0;
}
void hanoi(int n, char one, char two, char three) //将n个盘子从one借助two移向three
{
void move(char x, char y);
if(n == 1)
move(one, three);
else
{
hanoi(n - 1, one, three, two); //将n-1个盘子从one借助three移向two
move(one, three); //将底下的盘子从one移向three
hanoi(n - 1, two, one, three); //将n-1个盘子从two借助one移向three
}
}
void move(char x, char y)
{
printf("%c->%c\n", x, y);
}
在汉诺塔中,用递归就将一个庞大的任务一层层下放下去,同样的原理,只需要不断调用自己本身就可以,直到我们可以描述的情况停止。
递归的这种逻辑思想,极大地简化了思维,让我们将大工作分解为小工作,更好的解决问题。