递归的概念是数学和计算机科学的基本概念。在程序设计中递归程序的简单定义是一个能调用自身的程序,但一个递归程序不能总是调用自身,否则它将无法停止;所以递归还必须要有一个终止条件,使得程序能够停止调用自身。
递归算法是通过解决相同问题的一个或几个小例子来解决问题的算法。
我们先从简单的数学递归函数开始研究递归算法:
我们最熟悉的递归函数就是阶乘函数,
N!=N*(N-1)! , N>=1,0!=1
这个定义就对应了下面的算法






我们能够看到一个递归程序的基本特征:
1。它调用自身,return N*factorial(N-1);
2。有它要终止的条件,if(N==0)return 1。
递归如此的简单,并且很容易理解与设计,递归能使我们以简洁的形式表达复杂的算法,但递归使用了一个等同的内嵌堆栈。这会让我们在使用递归程序时,频繁的进出堆栈(尽管现代的编程系统都精心设计栈管理机制,但它依然不那么可靠),一不小心,效率就会大大降低,而且对于一个庞大的问题,栈所需要的空间可能会使我们无法承受,最终使程序不可用。
与这个递归函数factorial(int N)等效的循环如下:
for(t=1,i=1;i<=N;i++)t*=i;
我们将能够看到,任何一个递归程序总能转换成执行相同计算的非递归程序。
那么,我们使用递归程序,是因为递归更加自然并且容易使用数学归纳法进行证明,有利于我们分析程序设计的正确性。
学习递归,不能不讨论古老的汉诺塔问题:
我们有3个柱子和N个与柱子配套的盘子,这些盘子大小不同,而且最初从底端到顶端按从小(N)到小(1)的顺序放在其中一个柱子上。任务是按以下要求把所有盘子移动到最右边的柱子上:
1。一次只能移动一个盘子;
2。大的盘子不能放在小的盘子上。
传说当一群修道士在一个庙宇中把3个钻石柱子上的40个金盘子这样移动完成此任务,世界末日也就到了。
我们建立递归的是按如下的思想:
要把N个盘子从一个柱子移动到右边,先把柱子顶端的N-1个盘子移动到左边的柱子上;
然后把第N个盘子移动到右边;
然后再把N-1个盘子移动到左边(放到第N个盘子上),我们就完成了任务。
移动盘子时,当到达最右边的柱子时,循环到最左边的柱子;而到达最左边的柱子时,循环到最右边的柱子。










hanoi(n,d)中d为负数时,表示把盘子向左移;d为正数时,表示把盘子向右移。
在hanoi函数中,我们立刻得出盘子移动次数满足的递归公式:
T(N)=2T(N-1)+1 N>=2, T(1)=1
根据公式,我们可以知道T(N)=2^N-1
用归纳法证明:T(1)=2^1-1=1;假设T(N-1)=2^(N-1)-1成立,那么,T(N)=2T(N-1)+1=2(2^(N-1)-1)+1=2^N-1