>[success] # 汉诺塔
~~~
1.如下图所示,从左到右有A、B、C三根柱子,其中A柱子上面有从小叠到大的n个圆盘,现要求将A柱子上的圆盘移到
C柱子上去,期间只有一个原则:一次只能移到一个盘子且大盘子不能在小盘子上面,求移动的步骤和移动的次数
~~~
![](https://img.kancloud.cn/c0/12/c012707250c6a88bc648f1eb2b7a54af_586x209.png)
>[info] ## 栈的思路实现
~~~~
class Stack {
constructor() {
this.count = 0;
this.items = {};
}
push(element) {
this.items[this.count] = element;
this.count++;
}
pop() {
if (this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
}
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
isEmpty() {
return this.count === 0;
}
size() {
return this.count;
}
clear() {
/* while (!this.isEmpty()) {
this.pop();
} */
this.items = {};
this.count = 0;
}
toString() {
if (this.isEmpty()) {
return '';
}
let objString = `${this.items[0]}`;
for (let i = 1; i < this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
}
~~~~
>[danger] ##### 创建一个汉诺塔
~~~
1.汉诺塔,是三个柱子为基础,依次是'初始的源柱子上面依次摆放的要移动的盘子',
'辅助的柱子在将盘子转移到目标柱子时候辅助用的','目标柱子最后盘子要转移到的柱子'
2.我们将三个柱子看成三个栈,首先要做的就是创建三个柱子,并且个源柱子加上我们要
初始化的盘子
3.关于为什会看成三个栈,首先汉诺塔抽象化,就是一摞东西,无论你怎么操作,只能后进先出,
符合栈的定义,只是变化的是三者每次先后存放位置的顺序
~~~
~~~
// 汉诺塔
//----------------------------------------------------------------
// 创建一个汉诺塔
// @params plates 盘子个数
function hanoiStack(plates){
// 用三个栈 对象表示汉诺塔的三个柱子
/*
三个柱子依次表示为
source -- 最初始的柱子
dest -- 要移动到的目标柱子
helper -- 用来辅助移动的中间柱子
*/
const source = new Stack();
const dest = new Stack();
const helper = new Stack();
// 给 source 初始柱子 添加初始盘子
// 因为盘子是下往上依次是
for(let i=plates;i>0;i--){
source.push(i)
}
console.log(source)
// 后续需要移动盘子的发方法
return towerOfHanoi(plates, source, helper, dest, 'source', 'helper', 'dest');
}
~~~
>[danger] ##### 移动盘子的方法 -- towerOfHanoi
* 选自百度百科
~~~
1.当盘子的个数为n时,移动的次数应等于2^n – 1(有兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人
意料的简单方法,只要轮流进行两步操作就可以了。首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的
顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C;
若n为奇数,按顺时针方向依次摆放 A C B。
⑴按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A。
⑵接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较大的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。
⑶反复进行⑴⑵操作,最后就能按规定完成汉诺塔的移动。
所以结果非常简单,就是按照移动规则向一个方向移动金片:
如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C
~~~
![](https://img.kancloud.cn/6e/d2/6ed2bd9a2aa35873abf9bdcd92cae4b4_538x514.png)
~~~
/*
汉诺塔有三种情况其中两种是极端情况
1.第一种就是源柱没有盘子 相当于直接成功
2.第二种就是源柱只有一个盘子,直接移动一次就可以
3.非极端情况就是有一个以上的盘子需要我们平凡操作
*/
function towerOfHanoi(plates,source, helper, dest,helperName, sourceName, destName,moves=[]){
// 没有盘子就一次都不用移动,直接返回空
if(plates === 0) {
return moves
}else if(plates === 1){
// 直接将第一个移动到第三个
dest.push(source.pop())
const move = {}
move[sourceName] = source.toString()
move[helperName] = helper.toString()
move[destName] = dest.toString()
}else{
// 最复杂的多个盘子时候
// 三个柱子 看成动态,不在是固定功能位置
towerOfHanoi(plates - 1, source, dest, helper, sourceName, destName, helperName, moves);
dest.push(source.pop());
const move = {};
move[sourceName] = source.toString();
move[helperName] = helper.toString();
move[destName] = dest.toString();
moves.push(move);
towerOfHanoi(plates - 1, helper, source, dest, helperName, sourceName, destName, moves);
}
return moves;
}
hanoiStack(3)
~~~
* 打印结果
![](https://img.kancloud.cn/68/41/68416e78a28389d5db3532547a452ee7_494x148.png)
* A→C,A→B,C→B,A→C,B→A,B→C,A→C
~~~
function hanoi(plates, source, helper, dest, moves = []) {
if (plates <= 0) {
return moves;
}
if (plates === 1) {
moves.push([source, dest]);
} else {
hanoi(plates - 1, source, dest, helper, moves);
moves.push([source, dest]);
hanoi(plates - 1, helper, source, dest, moves);
}
return moves;
}
console.log(hanoi(3, 'A', 'B', 'C'));
~~~
![](https://img.kancloud.cn/1a/65/1a65125b8ca8f8c77ebd56cfcc846d6a_209x122.png)
- 接触数据结构和算法
- 数据结构与算法 -- 大O复杂度表示法
- 数据结构与算法 -- 时间复杂度分析
- 最好、最坏、平均、均摊时间复杂度
- 基础数据结构和算法
- 线性表和非线性表
- 结构 -- 数组
- JS -- 数组
- 结构 -- 栈
- JS -- 栈
- JS -- 栈有效圆括号
- JS -- 汉诺塔
- 结构 -- 队列
- JS -- 队列
- JS -- 双端队列
- JS -- 循环队列
- 结构 -- 链表
- JS -- 链表
- JS -- 双向链表
- JS -- 循环链表
- JS -- 有序链表
- 结构 -- JS 字典
- 结构 -- 散列表
- 结构 -- js 散列表
- 结构 -- js分离链表
- 结构 -- js开放寻址法
- 结构 -- 递归
- 结构 -- js递归经典问题
- 结构 -- 树
- 结构 -- js 二搜索树
- 结构 -- 红黑树
- 结构 -- 堆
- 结构 -- js 堆
- 结构 -- js 堆排序
- 结构 -- 排序
- js -- 冒泡排序
- js -- 选择排序
- js -- 插入排序
- js -- 归并排序
- js -- 快速排序
- js -- 计数排序
- js -- 桶排序
- js -- 基数排序
- 结构 -- 算法
- 搜索算法
- 二分搜索
- 内插搜索
- 随机算法
- 简单
- 第一题 两数之和
- 第七题 反转整数
- 第九题 回文数
- 第十三题 罗马数字转整数
- 常见一些需求
- 把原始 list 转换成树形结构