了解递归先从一个通俗例子开始
举一个通俗的例子:
有一个800g重的苹果要你切成重量相等的若干份,每一份的重量不能大于100g。你肯定会想到这样做:
1.第一刀先把一个苹果切成重量均等的2份A1和A2;
2.再把其中的一份A1切成重量均等的两份A11和A12, 把A2切成均等的两份A21和A22;
3.把A11切成均等的两份……
4.直到每一小份都小于等于100g为止。
递归就是 把一个大的事物化成若干个小的事物,每一次使用的方法都相同
更为专业的定义:
程序自身调用自身的编程技巧称为递归( recursion)。递归有直接递归和间接递归
•直接递归:函数在执行过程中调用本身。
•间接递归:函数在执行过程中调用其它函数再经过这些函数调用本身。
递归有四个特性:
1.必须有可最终达到的终止条件,否则程序将陷入无穷循环;
2.子问题在规模上比原问题小,或更接近终止条件;
3.子问题可通过再次递归调用求解或因满足终止条件而直接求解;
4.子问题的解应能组合为整个问题的解。
上面的例子中也满足以上的四点性质:
(1).终止条件是每一份的重量不能大于100g;
(2).每一次切的大小都比上一次小;
(3).每一次切的方式都相同,所以子问题可递归调用;
(4).最终切成的每一小份也就是要求的解。
汉诺塔问题之大象放入冰箱图解
将下面的三个柱子分别标记为 A B C都是一个可以放置盘子的容器,C可以看做是冰箱容器,最下层的红盘子可以看成是大象,红盘子上的所有盘子 看成是冰箱门。现在需要把盘子按大小一样的顺序从A放到C,限制要求:只许小盘子放在大盘子上,大盘子不能放在小盘子上
思考?
1 将汉诺塔问题转换成大象放进冰箱问题 最下层的红盘子可以看成是大象,红盘子上的所有盘子 看成是冰箱门
2 把冰箱门打开
移动上面所有盘子到中间位置
n-1表示红盘子上的所有盘子 看成是冰箱门
from表示从开始的柱子
in表示中间的柱子 帮到目标位置需要借助的柱子
to表示需要移到目标的柱子
hanoi(n-1,from,to,in);
此代码表示将冰箱门(即红盘子上的所有盘子)从from柱子借助目标to柱子移动到in柱子
3 把大象装进冰箱
移动最下面的一个盘子
将最后一个盘子(大象)放到冰箱(to)中
System.out.println("第"+n+"个盘子从"+from+"移到" + to);
4.把冰箱门关在冰箱上
将所有上面的盘子(冰箱门)中间位置(in)移动目标位置(to冰箱)
hanoi(n-1,in,from,to);
参数含义:n表示有n个盘子 都可以看成(n-1个盘子)冰箱门,最下层盘子(大象)
第一个参数from开始位置 第二个参数in需要借助的位置 第三个参数to移到的目标位置
public static void hanoi(int n,char from,char in,char to)
完整汉诺图代码:
TestHanoi.java 内容
package com.demo.node;
public class TestHanoi {
public static void main(String[] args) {
hanoi(3,'A','B','C');
}
/**
*
* @param n 共有n个盘子
* @param from 开始的柱子
* @param in 中间的柱子
* @param to 目标柱子
*/
public static void hanoi(int n,char from,char in,char to){
if(n == 1){
System.out.println("第1个盘子从"+from+"移到" + to);
}else{
//移动上面所有盘子到中间位置
hanoi(n-1,from,to,in);
//移动最下面的一个盘子
System.out.println("第"+n+"个盘子从"+from+"移到" + to);
//将所有上面的盘子中间位置移动目标位置
hanoi(n-1,in,from,to);
}
}
}
运行结果:当n=3
第1个盘子从A移到C
第2个盘子从A移到B
第1个盘子从C移到B
第3个盘子从A移到C
第1个盘子从B移到A
第2个盘子从B移到C
第1个盘子从A移到C