Python系列之一:汉诺塔(Hanoi)问题求解

一、问题背景

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。(来自百度百科)

二、任务描述

假设有A,B,C三座杆。在杆A上有n个直径各不相同、依次从小到大的编号为1,2.........,n的圆盘。现要求将A杆上的盘子全部移动到C杆上,并且要求:

1、每次只可以移动其中一根杆上的一只盘子。

2、每个盘子只能插在A,B,C其中一根杆上。

3、任何时刻任何杆上都不能出现较大盘子压在较小盘子上面的情况。

三、解决思路

该如何完成汉诺塔的任务呢?

当只有一个盘子时,即n=1。此时很简单,只要直接将A上的盘子移动到C上即可。

当n等于2时,则先要将第一个盘子移动到B上,再将第二个盘子移动到C上,最后将B上的盘子移动到C上。

依次类推,当n大于1的时候,可以考虑先将上面n-1个盘子通过A移动到B上,再将A上的最后一个盘子移动到C上,再将B上的n-1盘子通过A移动到C上。

这个显然是一个最适合递归的问题。

四、程序代码

1、算法一:简单粗暴型递归算法

# 递归法解hanoi塔问题
def move(n,fromSpike,toSpike):
    global count,top
    count+=1
    print(f"第{count}回合:{n} 从{fromSpike} 移到 {toSpike}")
    top[fromSpike]= '0' if str(n+1) in top.values() else str(n+1)
    top[toSpike]=str(n)

def tower(n,fromSpike,spareSpike,toSpike):
    if n==1:
        move(1,fromSpike,toSpike)
    else:
        tower(n-1,fromSpike,toSpike,spareSpike)
        move(n,fromSpike,toSpike)
        tower(n-1,spareSpike,fromSpike,toSpike)

count = 0
top={'A':'1','B':'0','C':'0'}
tower(4,'A','B','C')

2、算法二:堆栈式迭代算法

# 迭代堆栈法解hanoi塔问题
class Task:
    def __init__(self,num,top,fromSpike,toSpike,bufferSpike):
        self.num = num
        self.top = top
        self.fromSpike = fromSpike
        self.toSpike = toSpike
        self.bufferSpike = bufferSpike
    
    def __str__(self):
        return f"{self.num} | {self.top} | {self.fromSpike} | {self.toSpike} | {self.bufferSpike}"

    def move(self,count):
        print(f"第{count}轮:{self.top}从{self.fromSpike} 移到 {self.toSpike}")

class Stack:
    q=[]
    def __init(self):
        #self.q = []
        pass
    
    def push(self,o):
        self.q.append(o)
        #print("push:",self.q[-1])
        return self
        
    def pop(self):
        #print("pop:",self.q[-1])
        return self.q.pop()

    def isEmpty(self):
        return len(self.q)==0

def hanoi(num):
    def push(n,i,f,t,b):
        t = Task(n,i,f,t,b)
        tasks.push(t)

    tasks = Stack()
    push(num,1,'A','C','B')
    count =1
    while not tasks.isEmpty():
        task = tasks.pop()
        
        if task.num==1:
            task.move(count)
            count+=1
        else:
            push(task.num-1,1,task.bufferSpike,task.toSpike,task.fromSpike)
            push(1,task.num,task.fromSpike,task.toSpike,task.toSpike)
            push(task.num-1,1,task.fromSpike,task.bufferSpike,task.toSpike)
hanoi(4)

五、总结

两段代码,运行结果都是一样的。从代码量看,递归算法的实现无疑是最简洁的,而堆栈式算法则相对要复杂一点;但是从执行效率看,则堆栈式迭代算法要高效很多,因为如果N很大,则递归算法需要很大规模的嵌套运算,每一层计算需要等待深一层嵌套计算结果的完成,这个是系统资源无法承受的。

堆栈式迭代算法仍然是递归算法的思路,不过这个版本的实现很好解决了每次移动哪个圆盘的问题,而且无需使用三个堆栈来记忆每个杆的圆盘状态。

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值