递归的关键在于找出递归方程式和递归终止条件而不是去研究函数之间复杂的参数传递和调用关系,如果追随代码深入,糊涂是在所难免的。
其实递归在某种意义上也可以看做一种归纳方法。在数学归纳法中,第一步是递推的基础,第二步是递推的根据(称为立据,立据的假设称为归纳假设),具体如下: (1)验证P(n)当n=1时成立;(2)假设p(k)成立,推证P(k+1)成立;数学归纳法的核心,是在验证P(n),n=1时正确的基础之上,证明 P(n)具有递推性,两者缺一不可;
而作为一个递归,也应当具备这类似的两个条件。p(n)当n=1时成立,这相当于递归的出口,理论上无论在解决数学问题还是在设计递归函数中,这部分都是显而易见的。如果这个问题是个方程,将1代入,很容易证明等式成立,而在递归程序中,也是如此。如比较经典的汉诺塔问题,如果只有一个圆盘,我们直接将它移动到C柱上即可。二关键是第二个步骤。在数学中,我们会运用相关知识证明我们假设的成立。而在递归问题的解决中,我们不仅要证明这个问题是否可以用递归进行解决(通俗的说就是这个问题的解决是否每一步都执行相同的动作),而且要在代码中实现这种动作。还拿汉诺塔来说,在盘数超过1的情况下,我们会怎样做呢?首先,将n-1个盘移动到b柱,将a最下面的盘移动到c柱,再将b柱上的n-1个盘移动到c柱;
于是,我们可以得出解决汉诺塔问题的两个步骤:(1)在只有一个圆盘情况下的操作;(2)在盘数大于一情况下的操作,有了这两个步骤,我们就可以非常轻松的写出递归代码了,根本无需对问题层层深入。
附上汉诺塔问题的代码(转):
2 { printf("%c -> %c\n", start, finish);
3
4 }
5 void MoveTower(int count, char start, char finish, char temp)
6 { assert( count > 0 );
7 if (count == 1)
8 MoveSingleDisk(start, finish);
9 else
10 { MoveTower(count - 1, start, temp, finish);
11 MoveSingleDisk(start, finish);
12 MoveTower(count - 1, temp, finish, start);
13
14 }
15 }
16