汉诺塔非递归函数
Towers of Hanoi non-recursive function
我正在尝试找出如何在下面的函数 hanoi_2
中为河内塔问题实施非递归算法,但我不知道如何继续...
它抛出一个错误:"can't pop from empty list"。当我输入一个奇数时,它会以某种方式工作,但是,当第三个回合通过时,事情就出错了。当盘数输入为偶数时,程序甚至不启动。
怎么了?
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())
几乎没有错误。首先,交换是不正确的。替换后,A
和 B
引用同一对象。要么使用临时变量,要么使用 Python 语法:B, C, A = C, A, B
。其次,这种替换应该在 for
循环内完成,而不是之前。看看递归版本,你每次都改变塔的顺序。
我是用 phone 写的,所以我无法为您解决问题,但祝您好运!:-)
偶数盘的问题是堆栈交换不对:你似乎想循环三个堆栈(你这样做是错误的,因为你失去了对原始B列表的引用) ,而实际上你只需要交换 B 和 C 堆栈,你可以这样做:
B, C = C, B
该算法的问题是,虽然你有两个参与堆栈的权利(基于i%3
),你仍然必须确定两个参与堆栈中的一个是给予者,哪个是接受者,因为这并不总是一样的!最好为此编写一个函数,该函数接受两个堆栈并确定两个可能 "directions" 中的哪一个是有效的,然后执行该移动:
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())
现在主要算法如下所示:
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)
下面是递归等价的迭代解法。堆栈保存调用顺序及其状态。在这种情况下,堆栈上只有一个状态。
#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)
我正在尝试找出如何在下面的函数 hanoi_2
中为河内塔问题实施非递归算法,但我不知道如何继续...
它抛出一个错误:"can't pop from empty list"。当我输入一个奇数时,它会以某种方式工作,但是,当第三个回合通过时,事情就出错了。当盘数输入为偶数时,程序甚至不启动。
怎么了?
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())
几乎没有错误。首先,交换是不正确的。替换后,A
和 B
引用同一对象。要么使用临时变量,要么使用 Python 语法:B, C, A = C, A, B
。其次,这种替换应该在 for
循环内完成,而不是之前。看看递归版本,你每次都改变塔的顺序。
我是用 phone 写的,所以我无法为您解决问题,但祝您好运!:-)
偶数盘的问题是堆栈交换不对:你似乎想循环三个堆栈(你这样做是错误的,因为你失去了对原始B列表的引用) ,而实际上你只需要交换 B 和 C 堆栈,你可以这样做:
B, C = C, B
该算法的问题是,虽然你有两个参与堆栈的权利(基于i%3
),你仍然必须确定两个参与堆栈中的一个是给予者,哪个是接受者,因为这并不总是一样的!最好为此编写一个函数,该函数接受两个堆栈并确定两个可能 "directions" 中的哪一个是有效的,然后执行该移动:
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())
现在主要算法如下所示:
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)
下面是递归等价的迭代解法。堆栈保存调用顺序及其状态。在这种情况下,堆栈上只有一个状态。
#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)