问题
I'm trying to figure out how to implement a non-recursive algorithm for the Hanoi Towers problem in function hanoi_2
below, but I have no idea how to continue...
It throws an error: "can't pop from empty list". It works somehow when I input an odd number, however, when the third turn passes things go wrong. When an even number is input as the number of discs the program doesn't even start.
What is wrong?
from turtle import *
from tkinter import * # used for the dialog box
from tkinter.simpledialog import askinteger # used for the dialog box
from tkinter import ttk # used for the progress bar
import time # used for time-related functions (in pause)
import pickle # used to save an object to a file
class Disc(Turtle):
def __init__(self, n):
Turtle.__init__(self, shape="square", visible=False)
self.pu()
self.shapesize(1.5, n*1.5, 2) # square-->rectangle
self.fillcolor(n/10., 0, 1-n/10.)
self.st()
self.speed(11-n) # sets the speed of movement of the rectangles (the bigger, the slower)
self.moves = 0 # stores the number of times the disc is moved
class Tower(list):
"""Hanoi tower, a subclass of built-in type list"""
def __init__(self, x):
"""create an empty tower. x is x-position of peg"""
self.x = x
def push(self, d):
d.setx(self.x)
d.sety(-150+34*len(self))
d.clear()
d.write("Moved %s times" %(str(d.moves)), align="left", font=("Courier", 16, "bold"))
d.moves += 1 # increments the number of moves each time the disc is moved
self.append(d)
def pop(self):
d = list.pop(self)
d.sety(150)
return d
def hanoi(n, from_, with_, to_):
global moves
global ans
clear()
if n > 0:
hanoi(n-1, from_, to_, with_)
moves += 1 # amount of total moves is incremented
to_.push(from_.pop())
hanoi(n-1, with_, from_, to_)
sety(-255)
write("Total moves: %s" % (moves), align="center", font=("Courier", 16, "bold"))
sety(-320)
progress_bar(ans) # calls progress bar function
def hanoi_2(n, A, B, C):
global moves
clear()
if n%2==0:
B=C
C=A
A=B
for i in range(1,(2**n)-1):
if i%3==1:
C.push(A.pop())
if i%3==2:
B.push(A.pop())
if i%3==0:
B.push(C.pop())
回答1:
The issue with the even number of discs is that the stack swap is not right: you seem to want to cycle the three stacks (which you do in a wrong way as you lose the reference to the original B list), while actually you need to swap only the B and C stacks, which you can do as follows:
B, C = C, B
The issue with the algorithm is that although you have the involved two stacks right (based on i%3
), you must still determine which of the two involved stacks is the giver and which one the taker, as this is not always the same! It is probably best if you write a function for this that takes two stacks and determines which of the two possible "directions" is a valid one and then performs that move:
def validMove(A, B):
if not len(A):
A.push(B.pop())
elif not len(B):
B.push(A.pop())
elif A[-1] > B[-1]:
A.push(B.pop())
else:
B.push(A.pop())
Now the main algorithm will look like this:
for i in range(1,2**n):
if i%3==1:
validMove(A, C)
if i%3==2:
validMove(A, B)
if i%3==0:
validMove(B, C)
回答2:
There are few errors. First, swapping is incorrect. After your substitutions, A
and B
reference to the same object. Either use temporary variable, or use Python syntax: B, C, A = C, A, B
. Second, this kind of substitution should be done inside for
loop, not before. Look at recursive version, you change order of the towers each time.
I am writing from my phone so I cannot solve it for you, but good luck!:-)
回答3:
Below is a recursive and equivalent iterative solution. The stack saves the order of the calls and their state. In this case there is one state on the stack.
#recursive solution
def tower(numRings):
def tower1(numRings,fromPeg,toPeg,usePeg):
if numRings > 0: #A
tower1(numRings-1,fromPeg,usePeg,toPeg) #B
result.append((fromPeg,toPeg)) #C
tower1(numRings-1,usePeg,toPeg,fromPeg) #D
result = []
tower1(numRings,0,1,2)
return result
#iterative solution
def tower(numRings):
result = []
stk = []
def tower1(numRings):
In, To = 0, 1
stk.append((In,numRings,0,1,2))
while stk:
state,numRings,fromPeg,toPeg,usePeg = stk.pop()
if state == In:
if numRings != 0: #push down to 1 numRing #A
stk.append((To,numRings,fromPeg,toPeg,usePeg)) #B save state
stk.append((In,numRings-1,fromPeg,usePeg,toPeg))
elif state == To:
result.append((fromPeg,toPeg)) #C
stk.append((In,numRings-1,usePeg,toPeg,fromPeg)) #D
else:
print 'Error: logic'
return result
tower1(numRings)
return result
a = [1,2,3,4]
for n in a:
print 'rings',n
print tower(n)
来源:https://stackoverflow.com/questions/48913319/towers-of-hanoi-non-recursive-function