先讲个故事:
从前有座山,山里有座庙,庙里有个老和尚,老和尚对小和尚说,从前有座山,山里有座庙,庙里有个老和尚,老和尚对小和尚说,从前有座山…
其实这就是递归,所以我们每个人都听说过。
定义:递归就是自己调自己。
思想:是把规模较大的一个问题,分解成规模较小的多个子问题去解决,而每一个子问题又可以继续拆分成多个更小的子问题。 最重要的一点就是假设子问题已经解决了,现在要基于已经解决的子问题来解决当前问题;或者说,必须先解决子问题,再基于子问题来解决当前问题。
A依赖于B,B依赖于C,C依赖于D……
当D解决了那C就解决了,B解决了A就解决了。
1.求n的阶乘
则有:
n = 1,sum = 1
n = 2,sum = 21
n = 3,sum = 321
n = 4,sum = 4321
n = 5,sum = 54321
int GetSum (int n)
{
if (0 == n || 1 == n)
{
return 1;
}
else
{
return n*GetSum (n - 1);
}
}
结果:
通过大量的例子总结出递归需要注意一下几点:
- 第一递归函数功能
比如在这个函数中,功能就是求阶乘。 - 找出递归结束的条件
比如在这个函数中,递归终止条件就是n=0,n=1 - 找出函数的等价关系式
比如在这个函数中等价关系就是GetSum(n) = n*GetSum(n-1)
理解递归就是要多练习,多做题。
2.斐波那契数列问题
斐波那契数列的是这样一个数列:1、1、2、3、5、8、13、21、34…,即第一项 f(1) = 1,第二项 f(2) = 1…,第 n 项目为 f(n) = f(n-1) + f(n-2)。求第 n 项的值是多少。
函数如下:
int fibonaqie(int npos)
{
if (1 == npos||2 == npos)
{
//终止条件
return 1;
}
else
{
//等价关系
return fibonaqie(npos - 2) + fibonaqie(npos - 1);
}
}
3.爬楼梯问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析:
如果n=1,只有一种跳法,那就是1
如果n=2,那么有两种跳法,2,[1,1]
如果n=3,那么有三种跳法,[1,1,1],[1,2],[2,1]
如果n=4,那么有五种跳法,[1,1,1,1],[1,1,2],[1,2,1],[2,1,1],[2,2]
如果n=5,那么有八种跳法,[1,1,1,1,1],[1,1,1,2],[1,1,2,1],[1,2,1,1],[2,1,1,1],[2,2,1],[2,1,2],[1,2,2]
结果为1,2,3,5,8 这他妈不就是斐波那契数列嘛
下面看看代码
int GetCounts(int ntaijie)
{
if (0 >= ntaijie)
{
//终止条件
return 0;
}
if (1 == ntaijie)
{
//终止条件
return 1;
}
else if (2 == ntaijie)
{
//终止条件
return 2;
}
else
{
//等价关系
return GetCounts(ntaijie - 1) + GetCounts(ntaijie - 2);
}
}
4.汉罗塔问题:
问题来源:汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从上往下从小到大顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘,只能移动在最顶端的圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。
现在有n个圆盘从上往下从小到大叠在第一根柱子上,要把这些圆盘全部移动到第三根柱子要怎么移动呢?请找出需要步骤数最少的方案。
因此我们可以将问题简化描述为:n个盘子和3根柱子:A(源)、B(备用)、C(目的),盘子的大小不同且中间有一孔,可以将盘子“串”在柱子上,每个盘子只能放在比它大的盘子上面。起初,所有盘子在A柱上,问题是将盘子一个一个地从A柱子移动到C柱子。移动过程中,可以使用B柱,但盘子也只能放在比它大的盘子上面。
因此我们得出汉诺塔问题的以下几个限制条件:
1.在小圆盘上不能放大圆盘。
2.在三根柱子之间一回只能移动一个圆盘。
3.只能移动在最顶端的圆盘。
首先,我们从简单的例子开始分析,然后再总结出一般规律。
当n = 1的时候,即此时只有一个盘子,那么直接将其移动至C即可。移动过程就是 A -> C
其它情况可自行推演。
下面搞个图加深个印象:
void move(int n, char A, char B)
{
printf("将%d号盘子,从%c柱移动到%c柱\n", n, A, B);
}
//过渡柱不是固定的噢。
void hanluota(int nCounts,char A,char B,char C)
{
if (nCounts == 1)
{
move(1,A,C);
}
else
{
hanluota(nCounts - 1, A, C,B);//将n-个移动到过渡主子
move(nCounts, A, C);//此时剩下最后一个,将其移到到目标柱子
hanluota(nCounts - 1, B, A,C);//将剩下的过度住经过A移动到目标柱,此时A当作过度住
}
}
int main()
{
hanluota(3, 'A', 'B', 'C');
system("pause");
return 0;
}
运行结果:
我相信通过这些例子你应该对它有个初步的认识。