汉诺塔问题是一个神秘的题,今天我们一起来解开它神秘的面纱!
首先请看题
题目描述
汉诺塔是一个古老的数学问题:
有三根杆子A,B,C。A 杆上有 n 个 (n>1) 穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至 C 杆:
要求如下:
①每次只能移动一个圆盘;
②大盘不能叠在小盘上面。
提示:可将圆盘临时置于 BB 杆,也可将从 AA 杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则问:如何移?最少要移动多少次?
【解题思路】
汉诺塔问题只有两个要求,第一:每次只能移动最上面一个圆盘;第二:最后的C柱子上盘子应该是从大到小放置,而不是乱放。
根据常识很容易想到盘子的搬运方法,第一步:A柱子上共n个盘子,先将n-1个盘子全部依次放置到B柱子上,然后将A柱子上最大的盘子直接放到C柱子上,最后只需要依次将B柱子上的盘子依次摆放到C柱子上就OK! 这种重复性的搬运操作用计算机肯定能轻松解决,接下来我们只需要考虑用哪种算法便好。那么该使用哪种算法?稍微读一读题,很明显该题暗示我们的是盘子总数已经知道,只需要全部移到目的地。所以,A柱子上的盘子只会越来越少!算法呼之欲出----递归算法,digo搞定!
接下来便直接按照我们的逻辑写搬运的顺序就行,代码如下
#用递归方法解决汉诺塔问题:
#步骤一:将A柱的n-1个盘子移动到B柱
#步骤二:将A柱的最后一个盘子移动到C柱
#步骤三:将B柱的n-1个盘子移动到C柱
move_count=0 #总移动次数
def hanoi(p1,p2,p3,n):#传入三柱和盘子个数
global move_count
if n==1:#第二步,如果A柱只剩下一个盘子,则将盘子移动到C柱
print(p1,"->",p3)
move_count+=1
else:
hanoi(p1,p3,p2,n-1)#第一步,先将A柱n-1个盘子全部移动到B柱
print(p1,"->",p3)
hanoi(p2,p1,p3,n-1)#第三步,将B柱n-1个盘子全部移动到C柱
move_count+=1
hanoi("A","B","C",6)
print(move_count)
通过递归算法,我们简单就输出了运输过程和总的搬运次数,但是这只是思维过程的打印,空间内没有实际数据移动。如何更进一步,实现数据的真实移动? 如此,我们便需要思考该用哪种数据结构存储数据,并且该数据结构的增加和删除顺序符合柱子上盘子的增加和减少。只需要稍微思考,柱子上总是先放进去的盘子后拿出来,也就是后放进去的盘子会先拿出来,类比一下,这不就是栈? 所以,直接用栈存储数据就可以实现盘子的搬运! 注意:算法还是用递归,我们没改变算法啊
【看代码】
#利用堆栈数据结构模拟柱子移动盘子,每一个柱子就是一个堆栈
#先模拟一个栈
class Stack:
def __init__(self):#初始化栈
self.items=[]
def isEmpty(self):
if len(self.items)==0:
print("栈为空")
else:
print("栈不为空")
def push(self,iteam):
self.items.append(iteam)
def pop(self):
self.items.pop()
def top(self):
return self.items[len(self.items)-1]
#创建三个堆栈表示ABC三根柱子
a=Stack()
b=Stack()
c=Stack()
#count计算移动次数
count=0
#移动盘子
def move(p1,p2):
global count
value=p1.top()
p2.push(p1.top())
p1.pop()
count += 1
if p1==a and p2==b:
print("A->B,移动的盘子编号为:",value)
elif p1==a and p2==c:
print("A->C,移动的盘子编号为:",value)
elif p1 ==b and p2 ==c:
print("B->C,移动的盘子编号为:", value)
elif p1==b and p2==a:
print("B->A,移动的盘子编号为:", value)
elif p1==c and p2==a:
print("C->A,移动的盘子编号为:", value)
elif p1==c and p2==b:
print("C->B,移动的盘子编号为:", value)
#给A柱添加需要移动的盘子
n=int(input())
for i in range(n):
a.push(n-i)
def hanoi(p1,p2,p3,n):
if n==1:
move(p1,p3)
else:
hanoi(p1,p3,p2,n-1)
move(p1,p3)
hanoi(p2,p1,p3,n-1)
hanoi(a,b,c,n)
print("总移动次数是:",count)
a.isEmpty()
b.isEmpty()
c.isEmpty()
【总结】
有了栈存储数据模拟盘子的移动,我们不但可以知道移动过程和次数,而且还可以知道移动的是哪个盘子!通过最后的判空可以明显知道在存储空间中所有的数据均移动到C柱子上。由此更可知,算法是灵魂,数据结构是骨干,互相配合,相辅相成。