程序调用自身的编程技巧称为递归( recursion)。递归作为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
累加的递归实现本代码相对简单,不做进一步说明,在老师代码的基础上加入了少量的格式内容方便查看结果。
#includeint addTo(int paraN){ int tempSum; printf("entering addTo(%d)rn",paraN); if(paraN<=0){ printf(" return 0rn"); return 0; }else{ tempSum = addTo(paraN-1)+paraN; printf(" return %drn",tempSum); return tempSum; } } void addToTest(){ int n,sum; printf("---- addToTest begins. ----rn"); n=5; sum = addTo(n); printf("rn0 adds to %d gets %d.rn",n,sum); printf("----------------------rn"); n=1; sum = addTo(n); printf("rn0 adds to %d gets %d.rn",n,sum); printf("----------------------rn"); n=-1; sum = addTo(n); printf("rn0 adds to %d gets %d.rn",n,sum); printf("----------------------rn"); printf("---- addToTest ends. ----rn"); } void main(){ addToTest(); }
测试结果:递归实现汉诺塔问题---- addToTest begins. ----
entering addTo(5)
entering addTo(4)
entering addTo(3)
entering addTo(2)
entering addTo(1)
entering addTo(0)
return 0
return 1
return 3
return 6
return 10
return 150 adds to 5 gets 15.
----------------------
entering addTo(1)
entering addTo(0)
return 0
return 10 adds to 1 gets 1.
----------------------
entering addTo(-1)
return 00 adds to -1 gets 0.
----------------------
---- addToTest ends. ----
汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
- 每次只能移动柱子最顶端的一个圆盘;
- 每个柱子上,小圆盘永远要位于大圆盘之上;
把大象放进冰箱需要几步:
- 打开冰箱
- 把大象放进去
- 把冰箱门关上
把a柱的n个盘子移动到c柱需要几步:
- 把前n-1个盘子都移动到b柱
- 把最大的盘子(第n个)移动到c柱
- 把b柱上的n-1个盘子移动到c柱
如下
如果直接想全部n个的过程我们是比较难以想象的,但是因为递归的特性,我们只需写出第n个移动顺序即可。
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
if (paraN <= 0) {
return;
} else {
hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
printf("%c -> %c rn", paraSource, paraDestination);
hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
}
}
按照第n部的理解,我们需要先将小的块从a移到Transit,在将大的盘子移到Destination,最后将Transit的盘子移动到Destina,即上图的部分,最后推广到递归中,逐次将n减少,等到最终的函数。
汉诺塔问题的时间复杂度为O(2^n),空间复杂度为O(n)。
完整代码#includevoid hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) { if (paraN <= 0) { return; } else { hanoi(paraN - 1, paraSource, paraTransit, paraDestination); printf("%c -> %c rn", paraSource, paraDestination); hanoi(paraN - 1, paraTransit, paraDestination, paraSource); } } void hanoiTest() { printf("---- addToTest begins. ----rn"); printf("2 platesrn"); hanoi(2, 'A', 'B', 'C'); printf("3 platesrn"); hanoi(3, 'A', 'B', 'C'); printf("4 platesrn"); hanoi(4, 'A', 'B', 'C'); printf("---- addToTest ends. ----rn"); } void main() { hanoiTest(); }
测试结果:总结---- addToTest begins. ----
2 plates
A -> C
A -> B
C -> B
3 plates
A -> B
A -> C
B -> C
A -> B
C -> A
C -> B
A -> B
4 plates
A -> C
A -> B
C -> B
A -> C
B -> A
B -> C
A -> C
A -> B
C -> B
C -> A
B -> A
C -> B
A -> C
A -> B
C -> B
---- addToTest ends. ----
递归问题的关键在于找出最外层的函数规律。



