漢諾塔問題遞歸與非遞歸算法


漢諾塔問題遞歸與非遞歸算法

漢諾塔問題描述如下:

有 A、B、C 3 根針,n 個圓盤(從 1..n )從上到下,按小到大順序放在 A 處,要求每次移動一個,並保持從小到大的疊放順序,
利用 C,把 n 個盤子移動到 B 處。

遞歸算法

遞歸算法比較容易理解

fn hanoi(n):
    hanoi_move(n, 'A', 'B', 'C')

fn hanoi_move(n, from, to, medium):
    if n <= 0:
        return
    hanoi_move(n-1, 'A', 'C', 'B')
    println("move {} from {} to {}", n, from, to);
    hanoi_move(n-1, 'C', 'B', 'A')

非遞歸算法

重新思考整個移動過程,在處理 n 從 A 到 B 時,需要先處理其上的 n-1 個圓盤從 A 到 C,直到 A 處只剩下 1 個編號為 n 的圓盤,這個步驟定義為 Step :

struct Step {
    n, r, from, to, medium
}

r 表示當前編號為 n 其上面還放着有多少個圓盤,當 r 為 1 時,就可以移動編號為 n 的圓盤了,即:

Step(n, r, from, to, medium) 分解為
1. Step(r-1, r-1, from, medium, to)
2. Step(n, 1, from, to, medium)
3. Step(r-1, r-1, medium, to, from)

可利用棧或雙向隊列保存中間狀態,一直到分解完成,注意,用棧保存時方向與分解方向相反:

fn hanoi_move_stack(n, from, to, medium):
    if n <=0:
        return
    s = Stack()
    s.push(Step(n, n, from, to, medium)):
    while !s.is_empty():
        step = s.pop()
        if step.r == 1:
            println("move {} from {} to {}", step.n, step.from, step.to)
        else:
            s.push(Step(step.r-1, step.r-1, step.medium, step.to, step.from))
            s.push(Step(step.n, 1, step.from, step.to, step.medium))
            s.push(Step(step.r-1, step.r-1, step.from, step.medium, step.to))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM