最近XXX原因,比较久没写博客了,正好这会有点空就想写点东西。本来想写图相关算法,但是图相关东西比较多也比较复杂,一时也很难全面的写出来,即使写出来,也太零星反而更增加了读者的困惑。忽然想起来前两天有网友私信,说基础的递归如斐波那契算法能写出来,但是遇到稍微复杂点的就乱了,他看到小甲鱼教的汉诺塔算法懂原理了,但是看代码时还是感觉似懂非懂,理解的不是特别清晰。这个问题不大,几分钟就可以写好,正好适合现在写。博客链接:https://blog.csdn.net/wabiaozia/article/details/82822888
其实写递归时最简单的办法是递推出递归的公式,然后根据公式写递归。不过实际情况是,工作了不少年后不碰数学,对归纳公式有些抵触,碰到递归时更倾向于直接就开干,管他可不可以归纳出表达式。直接开干递归其实也有些技巧,防止你出现 '写代码时写着写着就乱了' 的问题。
如何设计递归算法:
1. 子问题须与原始问题为同样的事,且更为简单;
2. 不能无限制地调用本身,须有个出口,化简为非递归状况处理
递归算法更详细的介绍看:
1 https://www.bilibili.com/video/av7398130 用二进制来解汉诺塔问题
2 https://www.bilibili.com/video/av2975983/?p=34
3 https://blog.csdn.net/wabiaozia/article/details/82822888
我这里不介绍如何设计算法,直接开干汉诺塔。
什么是汉诺塔???汉诺塔hanoi:abc三根柱子,把a柱子上的n个盘子移动到c柱子上,每次只能移动一个盘子,移动的时候小盘子不能放在大盘子上。
- 把a柱子上的盘子看成两份,n作为一份,其余的n-1作为一份。把n-1作为一个整体移动到b柱子上(借助c柱子,c柱子作为中间站), 把 a柱子上最大的n盘子移到c柱子上。
- 然后把其余的b柱子上的n-1个盘子作为一个整体,借助a柱子(a柱子作为中间站),移动到c柱子上。
- 由于一次只能移动一个盘子,不能一次移动n-1个盘子,所以要把n-1个盘子再拆为两份,n-1为一份,其余的为一份。以此类 推。。。 如果还不能理解可以去看上面第二个视频。
前提:把盘子从a柱子移动到c柱子,b柱子作为中间站。则a为起点,c为落点,b为中间站。
理解汉诺塔代码的核心在下面两句话(私信网友糊涂的点估计在这里):
- 每次这个方法传进来4个参数,第0个位置盘子数,第一个位置是起点,第二个位置是中间站,第三个位置是落点。见下图标示。
- 传进来的abc放在hanoi方法参数的不同位置,即可改变下次执行的起点中间站落点。举例1:hanoi(n,a,c,b) 下次执行时即a为起点,c为中间站,b为落点 。 举例2:hanoi(n,b,a,c) 下次执行时b为起点,a为中间站,c为落点。详见代码里注释
public static void main(String[] args) {
int n=5;
Hannii hannii = new Hannii();
String a = "a";
String b="b";
String c="c";
hannii.hanoi(n,a,b,c);
}
// 前提:把盘子从a柱子移动到c柱子,b柱子作为中间站。则a为起点,c为落点,b为中间站。
// *****注意****//我的博客 https://blog.csdn.net/wabiaozia/article/details/82822888
// 1 这个方法传进来4个参数,第0个位置盘子数,第一个位置是起点,第二个位置是中间站,第三个位置是落点。
// 2 传进来的abc放在hanoi方法参数的不同位置,即可改变下次执行的起点中间站落点。举例1:hanoi(n,a,c,b) 下次执行时即a为起点,c为中间站,b为落点 。
// 举例2:hanoi(n,b,a,c) 下次执行时b为起点,a为中间站,c为落点。
private void hanoi(Integer n, String a, String b, String c) {
if (n==1) {
System.out.println(a+"----->----->"+c);
}else {
// 盘子从a移动到b,用c作为中间站。见举例1
// 解释下把传进来的参数怎么放:这次递归的起点即hanoi方法的第一个参数,怎么放?把参数里传进来的a放到第一个参数位置。
// 这次递归的落点即hanoi方法的第二个参数,怎么放?把参数里传进来的 b放到第三个位置。
// 这次递归的中间站即hanoi方法的第三个参数,怎么放?把 参数传进来的 c放到第二个位置。
hanoi(n-1, a, c, b);
//我的博客 https://blog.csdn.net/wabiaozia/article/details/82822888
move(a,c);
// 盘子从b移动到c,用a作为中间站,见举例2。这轮递归起点:参数里传进来的from。 这轮递归的中间站: 参数传进来的 to。 这轮递归的落点:参数里传进来的 inner。
hanoi(n-1, b, a, c);
}
}
private void move(String a, String c) {
System.out.println(a+"----->"+c);
}
转载请标明连接:https://blog.csdn.net/wabiaozia/article/details/82822888
我博客所有文章链接:https://blog.csdn.net/wabiaozia