在说汉诺塔之前,我们先来看看递归的概念。
递归的体现就是函数自身调用函数自身
递归主要解决什么问题呢?
- 一般而言,但凡能够被迭代(循环)解决的问题,递归都可以
- 递归解决的问题,迭代就不一定了
- 递归其实是分治法的一种实现方式(一种实现思路)
- 递归就是函数进栈,进栈的次数多了,势必会占内存,无法避免的
- 在某些问题上,递归所写的代码要比迭代写的代码少
- 在某些问题上,迭代是写不出来的,所以只能用递归
分治法是一种算法思想,分治法主要解决的问题是将大问题,进行拆分,拆分成若干个小的问题进行求解,最终将每个小问题的解进行合并。
其实,分治法就是一种暴力破解法(穷举),也是一种搜索最优答案的算法
递归:先递,后归
- 前进段---指的就是讲问题从大化小
- 结束段--- 问题无法再继续化小,则处理当前的问题
- 返回段---将小问题处理完毕之后,向上返回(有些问题是不需要返回的)
汉诺塔:汉诺塔(又称河内塔)问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
今天看到这个问题,我还在想可以直接全部放在中间的柱子上,然后再一个一个移到目标柱子上,但是其实大盘子必须在小盘子的下面,这种做法就行不通了。
那么我们在进行转移时,必须保持大盘在小盘下面,且每次只能移动一个圆盘,最终也是按照从上到下按从小到大的顺序
现在就来一点一点分析:我们先以3个圆盘为例,用一段动画解释一下
其中,X是起始begin,Y是中间middle,Z是结束end
我们可以看到,移动的顺序为:X->Z X->Y Z->Y X->Z Y->X Y->Z X->Z
将它稍作分类:三个圆盘 X->Z
前两个X->Y
前1个 X->Z
第2个 X->Y
前1个 Z->Y
第3个 X->Z
前2个 Y->Z
前1个 Y->X
第2个 Y->Z
前1个 X->Z
class Hanno{
public static void main(String[] args){
//盘子的个数 出发 中间 目的
hanno(3,"X","Y","Z");
}
public static void hanno(int n,String begin,String mid,String end){
if(n==1){
System.out.println(begin+" -> "+end);
}else{
hanno(n-1,begin,end,mid);
System.out.println(begin+" -> "+end);
hanno(n-1,mid,begin,end);
}
}
}
来看一下结果:
分析完三个,我们再来看看64个
我们可以将64个圆盘分成两部分,第一部分:前63个盘子;第二部分:第64个盘子,那我们这时候就相当于只有两个盘子。那我们现在就忽略第64个盘子,先移动前63个,我们再将63个盘子分成前62个和第62个,以此列推,直到转移完毕。
那么,我们就可以写出代码
class Hanno{ public static void main(String[] args){ //盘子的个数 出发 中间 目的 hanno(64,"X","Y","Z"); } public static void hanno(int n,String begin,String mid,String end){ if(n==1){ System.out.println(begin+" -> "+end); }else{ hanno(n-1,begin,end,mid); System.out.println(begin+" -> "+end); hanno(n-1,mid,begin,end); } } }
这个结果很大,我就不展示了,也展示不了,不知道什么时候能算完!
这道题代码看着简单,但是其中的逻辑思维很复杂,得细细品。
那么今天关于汉诺塔的分享就结束了,希望大家可以有不同的想法来交流交流!