【棧與隊列】求解漢諾塔問題(1.用遞歸的方式)

功能需求

事先聲明:博主在一本算法書上看到這個問題,對此有一些想法,有一部分出自抄騰,博主一心想表達自己對於處理問題的觀點.對於此無需註明轉發出處.此漢諾塔問題遞歸算法並未解決柱子還原之前不能爲空問題,此種方法還有待優化.

        漢諾塔問題一直是數據算法結構中比較經典的一個問題,但是還需要略微解釋一下:相傳在古印度聖廟中,有一種被稱爲漢諾塔(Hanoi)的遊戲。該遊戲是在一塊銅板裝置上,有三根杆(編號A、B、C),在A杆自下而上、由大到小按順序放置64個金盤(如下圖)。遊戲的目標:把A杆上的金盤全部移到C杆上,並仍保持原有順序疊好。操作規則:每次只能移動一個盤子,並且在移動過程中三根杆上都始終保持大盤在下,小盤在上,操作過程中盤子可以置於A、B、C任一杆上。在這裏我們來修改一下遊戲規則:現在限制不能從最左側的塔直接移動到最右側,也不能從最右側的塔直接移動到最左側,而必須經過中間。但當求N層的時候,打印最優的移動過程和最優的移動總步數。

       例如:當塔層數爲兩層時,最上層的塔標記爲1,最下層的塔標記爲2,這打印:

           Move 1 from left to mid

           Move 1 from mid to right

           Move 2 from left to mid

           Move 1 from right to mid

           Move 1 from mid to left

           Move 2 from mid to right

           Move 1 from left to mid

           Move 1 from mid to right

           It will move 8 steps。

要求:可以使用遞歸和非遞歸兩種方法做,非遞歸算法用棧來模擬漢諾塔的三個塔。

詳細解析

        遞歸的方法:首先,如果只剩最上層的塔需要移動,這需要有如下處理結果(左中右的移動方式)可以作爲遞歸的終止條件,也就是只剩下上層塔的時候需要打印的結果。

  1、如果希望從“左”移動到“中”,打印“Move 1 from left to mid”;

  2、如果希望從“中”移動到“左”,打印“Move 1 from mid to left”;

  3、如果希望從“中”移動到“右”,打印“Move 1 from mid to right”;

  4、如果希望從“右”移動到“中”,打印“Move 1 from right to mid”;

  5、如果希望從“左”移動到“右”,打印“Move 1 from left to mid”和“Move 1 from mid to right”;

  6、如果希望從“右”移動到“左”,打印“Move 1 from right to mid”和“Move 1 from mid to left”;

        如果剩下N層塔了,從上到下依次是1~N,這有以下判斷。

1、如果剩下的N層塔都在“左”,希望全部移動到“中”,這需要三個步驟:

    a.將1~N-1層塔全部從“左”移動到“右”,則交給遞歸過程;

    b.將第N層塔從“左”移動到“中”;

    c.再將1~N-1層塔全部從“右”移動到“中”,這個也交給遞歸過程

2、如果把剩下的N層從“中”移動到“左”,從“中”移動到“右”,從“右”移動到“中”,過程與情況1大致相同。
3、如果剩下的N層塔都在“左”,希望全部都要移動到“右”邊去。則有五個步驟:
    a.將1~N-1層塔先全部從“左”移動到“右”,由遞歸來完成.
    b.將第N層塔從“左”移動到“中”.
    c.將1~N-1層塔全部從“右”移動到“左”,由遞歸來完成.
    d.將第N層塔從“中”移動到“右”.
    e.最後將1~N-1層塔全部從“左”移動“右”,由遞歸來完成.
4、如果剩下的N層塔都在“右”塔,希望全部移動到“左”,過程與3基本一致,一樣是分爲五個步驟:
    a.將1~N-1層塔先全部從“右”移動到“左”,由遞歸來完成.
    b.將第N層塔從“右”移動到“中”.
    c.將1~N-1層塔全部從“左”移動到“右”,由遞歸來完成.
    d.將第N層塔從“中”移動到“左”.
    e.最後將1~N-1層塔全部從“右”移動“左”,由遞歸來完成.
以上則爲規律性詳細解釋。

代碼實現

代碼實現:
package com.hekaikai666.test3;

/**
 * 漢諾塔問題
 * @author hekaikai666
 * @time 2018年8月27日下午3:37:14
 **/
public class hanoiProblem {
        // 定義方法出啊如左中右的值
    public int hanoiProblem1(int num, String left, String mid, String right) {
	if (num < 1) {
	    return 0;
	}
	return process(num, left, mid, right, left, right);
    }
        // 顯示傳遞的方法,邏輯
    public int process(int num, String left, String mid, String right, String from, String to) {
	if (num == 1) {
	    if (from.equals(mid) || to.equals(mid)) {
		System.out.println("Move 1 from " + from + " to " + to + ";");
		return 1;
	    } else {
		System.out.println("Move 1 from " + from + " to " + mid + ";");
		System.out.println("Move 1 from " + mid + " to " + to + ";");
		return 2;
	    }
	}
	if (from.equals(mid) || to.equals(mid)) {
	    String another = (from.equals(left) || to.equals(left)) ? right : left;
	    int part1 = process(num - 1, left, mid, right, from, another);
	    int part2 = 1;
	    System.out.println("Move " + num + " from " + from + " to " + to + ";");
	    int part3 = process(num - 1, left, mid, right, another, to);
	    return part1 + part2 + part3;
	} else {
	    int part1 = process(num - 1, left, mid, right, from, to);
	    int part2 = 1;
	    System.out.println("Move " + num + " from " + mid + " to " + to + ";");
	    int part3 = process(num - 1, left, mid, right, to, from);
	    int part4 = 1;
	    System.out.println("Move " + num + " from " + mid + " to " + to + ";");
	    int part5 = process(num - 1, left, mid, right, from, to);
	    return part1 + part2 + part3 + part4 + part5;
	}
    }
}

總結分析

   僅僅使用遞歸算法就是不斷的判斷移動的位置和兩邊位置的不同當然 這樣處理會很麻煩,因爲不斷的調用當前的值,然後去判斷下一個,這樣難度就好像幾何倍數的增加,但是我們有沒有一種方法能夠使用性處理運算呢,就比如說,我們挪動的時候只需要考慮存放的位置而不去考慮左右的大小,那麼我們可以選擇使用棧的非遞歸方式來處理,反而更加簡便.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章