簡體   English   中英

河內塔非遞歸函數

[英]Towers of Hanoi non-recursive function

我試圖弄清楚如何在下面的函數hanoi_2中為 Hanoi Towers 問題實現非遞歸算法,但我不知道如何繼續......

它拋出一個錯誤: “無法從空列表中彈出” 當我輸入一個奇數時,它以某種方式工作,但是,當第三個回合過去時,事情就出錯了。 當輸入偶數作為光盤數時,程序甚至不啟動。

怎么了?

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())

偶數盤的問題在於堆棧交換不正確:您似乎想要循環三個堆棧(因為您丟失了對原始 B 列表的引用,所以您以錯誤的方式進行了操作),而實際上您需要僅交換 B 和 C 堆棧,您可以執行以下操作:

B, C = C, B

該算法的問題在於,盡管您擁有正確的兩個堆棧(基於i%3 ),您仍然必須確定兩個相關堆棧中的哪一個是給予者,哪一個是接受者,因為這並不總是相同的! 最好為此編寫一個函數,該函數需要兩個堆棧並確定兩個可能的“方向”中的哪一個是有效的,然后執行該移動:

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)

錯誤很少。 首先,交換是不正確的。 替換后, AB引用同一個對象。 要么使用臨時變量,要么使用 Python 語法: B, C, A = C, A, B 其次,這種替換應該在for循環內部完成,而不是之前。 看看遞歸版本,你每次都改變塔的順序。

我正在用手機寫信,所以我無法為您解決,但祝您好運!:-)

下面是一個遞歸和等效的迭代解決方案。 堆棧保存調用的順序及其狀態。 在這種情況下,堆棧上只有一個狀態。

#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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM