前奏
小时候,大家可能都听过这样一个故事:从前有座山,山里有座庙,庙里有个老和尚,在给小和尚讲故事。讲的什么故事呢?从前有座山,山里有座庙,庙里有个老和尚,在给小和尚讲故事。讲什么故事呢?从前有座山,山里有座庙,庙里有个老和尚,在给小和尚讲故事。讲的什么故事呢?从前有座山,山里有座庙,庙里有个老和尚,在给小和尚讲故事。。。。。。
这个故事也算是一个递归的表现,只不过它是一个死递归,会造成栈溢出异常
那什么是递归呢?请看下面
什么是递归?
- 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法
- 它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解
- 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
递归的四条基本法则(重点)
- 基准情形:必须总要有某些基准情形,它无需递归就能解出
- 不断推进:对于那些需要递归递归求解的情形,每一次递归调用都必须要使状况朝向一种基准情形推进
- 设计法则:假设所有的递归调用都能运行
- 合成效益法则:在求解一个问题的同一实例时,切勿在不同的递归调用中做重复性的工作
递归需要的一些问题
- 能循环绝不递归
- 递归时一定要满足四条基本法则
学习递归时,常常会有些同学用递归来计算 斐波那契数列 ,但是这并不是一个好主意,原因就是它不满足递归的第四条基本法则
递归的经典案例(汉诺塔问题)
- 游戏规则:
已知有三根柱分别用A, B, C表示,在A中从上到下依次放n个从小到大的盘子,现要求把所有的盘子从A针全部移到C柱 - 移动规则是:
可以使用B柱临时存放盘子,每次只能移动一块盘子,而且每根柱不能出现大盘压小盘,找出移动次数最小的方案 - 代码实现:
package cn.edu.xiyou.demo2;
//递归实现汉诺塔游戏
public class myHanoi {
public static void main(String[] args) {
hanoi(4,"A柱","B柱","C柱");
}
/**
*
* @param n 汉诺塔游戏的环数(总共有多少个环)
* @param from 起始位置(A柱)
* @param in 中间位置(B柱)
* @param to 目标位置(C柱)
*/
//自己根据网上的汉诺塔游戏就能理解该方法的作用0]y
private static void hanoi(int n, String from, String in, String to) {
//只有一个环的情况
if(n==1){
System.out.println("第1个盘子从"+from+"移到"+to);
//大于一个环时的情况
}else {
//递归调用方法,将最底层环以上的环由起始位置(A柱)全部移到中间位置(B柱),以便把最底层环移到目标位置(C柱)
hanoi(n-1,from,to,in);
//将最底层的环移到目标位置(C柱)
System.out.println("第"+n+"个盘子从"+from+"移到"+to);
//递归调用方法,将最底层环以上的环从中间位置(B柱)又移到目标位置(C柱)
hanoi(n-1,in,from,to);
}
}
//可以跟着执行结果一步一步完成游戏,你可以发现没有任何毛病,哈哈
}