最近在学算法,遇到典型的汉诺塔问题,就想把自己的一些认识总结一下与大家分享。
算法起源
汉诺塔问题是数据结构与算法经典问题之一,是源于印度一个古老传说的益智游戏。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
算法原理
面对这样的问题,我们一开始可能会手足无措,觉得很难(至少一开始我是这么觉得的)。碰到一个算法问题时,首先不要乱,先分析这个问题有什么特征,再根据特征决定采用什么方法来解决。先来明确一下目标:将左边的盘子移动到右边的柱子上,其中大的盘子不能放在小的盘子上方。
|
|
那么,我们想实现这个目标,也就是意味着最长的绿色盘子要位于右边柱子的最底部,在把绿色盘子放到右边柱子之前,绿色盘子上面的蓝色和红色盘子就必须先放在中间的柱子上,如下图:
只有这样才能轮到绿色盘子移动到右边柱子。也就是说要想移动三个盘子到右边柱子,那么之前必须先把前两个盘子移动到中间柱子上。依次类推,移动n个盘子,可以拆解为:将前n-1个盘子移动到中间柱子,再把第n个盘子移动到右边柱子。
既然我们已经将问题拆解成子问题,那么我们就可以用递归方法来解决这个问题。
图解步骤
|
|
|
|
|
|
|
|
代码实现
Hanoi.h
#pragma once
#ifndef HANOI_H
#define HANOI_H
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define OK 1;
#define ERROR 0;
#define TRUE 1;
#define FALSE 0;
//#define MAXSIZE 40;
const int MAXSIZE = 40;
typedef int Status;
typedef char String[MAXSIZE + 1];
Status StrAssign(String T, char *chars);
void StrPrint(String T);
void transfer(int n, String srcPole, String destPole);
void Hanoi(int n, String srcPole, String tempPole, String destPole);
#endif // !HANOI_H
Hanoi.cpp
#include"Hanoi.h"
int step = 0;
void Hanoi(int n, String srcPole, String tempPole, String destPole) {
if (n < 1)
printf("输入层数无效");
else if (n == 1)
transfer(n, srcPole, destPole);
else {
Hanoi(n - 1, srcPole, destPole, tempPole);//将前n-1个盘子移动到中间柱子
transfer(n, srcPole, destPole);//将第n个盘子移动到右边柱子
Hanoi(n - 1, tempPole, srcPole, destPole);//将中间柱子的n-1个盘子移动到右边柱子
}
return;
}
Status StrAssign(String T, char *chars) {
int i;
if (strlen(chars) > MAXSIZE)
{
return ERROR;
}
else
{
T[0] = strlen(chars);
for (i = 1; i <= T[0]; i++) {
T[i] = *(chars + i - 1);
return OK;
}
}
}
void StrPrint(String T) {
int i;
int l = strlen(T);
for (i = 1; i <= l; i++) {
printf("%c", T[i]);
}
}
void transfer(int n, String srcPole, String destPole) {
printf("将%d从", n);
StrPrint(srcPole);
printf("移动到");
StrPrint(destPole);
printf("\n");
step += 1;
}
演示程序
这里提供一个网上的python脚本,上述的图片都是源自此程序。
import turtle
import time
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
if not self.isEmpty():
return self.items[len(self.items) - 1]
def size(self):
return len(self.items)
def drawpole_3():#画出汉诺塔的底座
t = turtle.Turtle()
t.hideturtle()
def drawpole_1(k):
t.up()
t.pensize(5)
t.speed(75)
t.goto(200*(k-1), 100)
t.down()
t.color('purple')
t.goto(200*(k-1), -100)
t.goto(200*(k-1)-20, -100)
t.goto(200*(k-1)+20, -100)
drawpole_1(0)#画出汉诺塔的A
drawpole_1(1)#画出汉诺塔的B
drawpole_1(2)#画出汉诺塔的C
def creat_plates(n):#制造n个盘
plates=[turtle.Turtle() for i in range(n)]
col = ["green","red","blue","yellow"]
for i in range(n):
plates[i].up()
plates[i].color(col[i % len(col)])
plates[i].hideturtle()
plates[i].shape("square")
plates[i].shapesize(1,9-i)
plates[i].goto(-200,-90+20*i)
plates[i].showturtle()
return plates
def pole_stack():
poles=[Stack() for i in range(3)]
return poles
def moveDisk(plates,poles,fp,tp):
mov=poles[fp].peek()
plates[mov].goto((fp-1)*200,150)
plates[mov].goto((tp-1)*200,150)
l=poles[tp].size()
plates[mov].goto((tp-1)*200,-90+20*l)
def moveTower(plates,poles,height,fromPole, toPole, withPole):
if height >= 1:
moveTower(plates,poles,height-1,fromPole,withPole,toPole)
moveDisk(plates,poles,fromPole,toPole)
time.sleep(2)
poles[toPole].push(poles[fromPole].pop())
moveTower(plates,poles,height-1,withPole,toPole,fromPole)
if __name__ == "__main__":
myscreen=turtle.Screen()
drawpole_3()
n=eval(input(""))
plates=creat_plates(n)
time.sleep(2)
poles=pole_stack()
for i in range(n):
poles[0].push(i)
moveTower(plates,poles,n,0,2,1)
myscreen.exitonclick()
如有侵权,请告知删除。