1.分治算法介绍
分治算法在算法中是很重要的算法。简单明了就是先分而治。就是把一个问题分成多个相同或者相似的子问题,再把子问题分成更小的子问题,直到最后子问题可以简单的直接求解,原问题的解即是子问题的解的合并。很多常用的高效算法(快速排序,归并排序,二分搜索......)都是以分治算法为基础的
2.分治算法基本步骤
分治算法在每一层的递归上可分为三个步骤
- 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题
- 解决:若子问题规模较小而容易被解决则直接解,否则递归的解各个子问题
- 合并:将各个子问题的解合并为原问题的解
3.汉诺塔问题
3.1.汉诺塔背景
汉诺塔 (Tower of Hanoi),又称 河内塔 ,是一个源于 印度 古老传说的 益智玩具 。 大梵天 创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。 大梵天命令 婆罗门 把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。 并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。 汉诺塔的来源 法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石针。 印度教的主神 梵天 在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片金片,这就是所谓的汉诺塔。
3.2.实现
我们这里把三根柱子分别叫做A,B,C,初始盘都放在A柱,目标要放入C柱
- 如果只有一个圆盘,那我们直接把圆盘从A->C
- 如果圆盘数n>=2,那我们就可以把圆盘看成两个盘,1.最上面的盘 2.最下面的盘
- 那我们的大步骤就只有三步
-
先把最上面的所有盘 A->B
-
把最下面的盘A->C
-
把B塔的所有的盘B->C
-
- 这里就用到了分治,以我们三个盘举例,最上面的盘有两个,目标是移动到B柱,那我们就假设把B柱和C柱换个位置,这就相当于我么移动两个盘移动到目标柱,那还是把这两个盘分上盘和下盘,上面第一个盘得到目前的C柱子,最下面的盘到B柱子,再把目前C柱子上的盘移动到B柱子,也就是我上面写的三步。如果是四个盘我们最上面就是三个盘移动到实际的B柱子,那我们最上面的三个盘又分治成最上面两个盘移动。
- 根据4.我们已经把最上面的盘移动到B柱,那我们最下面的盘就从A->C
- 然后我们再把B柱上的所有盘移动到C柱子,
- 这里我们又可以看成是两个盘要移动到目标为C的柱
- 就要先把最上面的盘移动到A柱子,再把最下面的盘子移动到C柱
- 我们可以把柱子的顺序看成B,A,C,然后重复那三步
3.3.具体代码
我这里使用Java演示代码实现
//这里的char c 始终要是我们的目标柱子 ,char a 传的始终是我们的初始柱子(即要移动的盘子所在的位置)
public static void hanoiTower(int num ,char a ,char b ,char c){
//如果只有一个盘,初始柱子a 目标柱子就是c直接从a->c
if(num == 1){
System.out.println("第1个盘从 " + a + "->" + c);
}else {
//如果我们有n => 2情况 ,我们总是可以看做是两个盘 ,最下面的盘,最上面的盘
//1.先把最上面的所有盘 A->B,那我们的初始柱子a,目标柱子就是b,所有把b传给char c
hanoiTower(num -1 ,a,c,b);
//2.把最下面的盘A->C
System.out.println("第"+num+"个盘从 "+ a + "->" + c);
//3.把B塔的所有的盘B->C 初始柱子b,目标柱子c ,所有把b传给char a
hanoiTower(num - 1 , b , a ,c);
}
}
注:讲的不是很详细,可以先去听听尚硅谷的《数据结构与算法(Java数据结构与算法)》p155 ,如果不理解再来看看这个。