漢諾塔問題算法

問題

漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候作了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序從新擺放在另外一根柱子上。而且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。java

遞歸算法

在這裏插入圖片描述
咱們這裏先列舉盤子的個數爲1,2,3,4的時候的狀況,具體的以下表格。
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
觀察上面的四個表格數據,咱們能夠獲得如下結論: 1.移動的步數一定爲奇數步 2.(1)中間一步是把最大的一個盤子由A移動到C上去 (2)中間一步之上能夠當作把A上n-1個盤子經過藉助輔助塔(C塔)移到了B上 (3)中間一步之下能夠當作把B上n-1個盤子經過藉助輔助塔(A塔)移到了C上

非遞歸算法

一個美國學者總結獲得:全部的漢諾塔移動能夠總結爲重複的兩步。 咱們假設如今最小的圓盤在A柱子上,柱子爲A,B,C 第一步:將最小圓盤移動到下一個柱子上,也就是B 第二步:對A柱子和C柱子進行頂上最小的元素進行判斷,把小一點的那個圓盤移動到大一點的那個圓盤(有空則摞在空柱子上)。 重複上述兩步就能夠獲得答案。注意:這樣獲得的最後的答案不必定是摞在C上,若是N是奇數將摞在B上,因此若是N是奇數咱們就令第二個柱子爲C,第三個柱子爲B,這樣就必定最後是摞在C上的。算法

爲了形象地說明這個過程,下面以n=3時爲例 bash

在這裏插入圖片描述

實現代碼

解決漢諾塔問題的算法代碼以下:學習

package com.general.arithmetic.practice;

import java.util.ArrayList;
import java.util.Stack;

/***
 * 漢諾塔問題的學習與練習
 * 問題描述:從左到右有A、B、C三根柱子,其中A柱子上面有從小疊到大的n個圓盤,現要求將A柱子上的圓盤移到C柱子上去,期間只有
 * 一個原則:一次只能移動一個盤子且大盤子不能在小盤子上面,求移動的步驟和移動的次數。
 *
 * 漢諾塔的非遞歸算法:
 * 一個美國學者總結獲得:全部的漢諾塔移動能夠總結爲重複的兩步,咱們假設如今最小的圓盤在A柱子上,柱子A、B、C
 * 第一步:將最小圓盤移動到下一個柱子上,也就是B
 * 第二步:對A柱子和C柱子進行頂上最小的元素進行判斷,把小一點的那個圓盤移動到大一點的那個圓盤(有空則放置在空柱子上)
 * 重複上述兩步就能夠獲得答案。
 *
 * **/
public class Hanoi {
    public static int count=0;
    public static Stack<Integer> plate=new Stack<Integer>();
    public static int PLATE_COUNT=3;

    public static ArrayList<Stack<Integer>> plate_array=new ArrayList<>();
    public static char s[]={'A','B','C'};

    public static void move_recursion(int n,char A,char C){

        count++;
        System.out.println("plate "+plate.search(n)+" move:"+A+"-------->"+C);
    }
    public static void hanoi_tower(int n,char A,char B,char C){

        if(n==1){
            move_recursion(1,A,C);
        }else{
            hanoi_tower(n-1,A,C,B);
            move_recursion(n,A,C);
            hanoi_tower(n-1,B,A,C);
        }
    }
    public static boolean move(int before,int after){
        if(plate_array.get(before).empty()){
            return false;
        }
        if (!plate_array.get(after).empty()){
            if((plate_array.get(after).peek()-plate_array.get(before).peek())<0){
                return false;
            }
        }
        plate_array.get(after).push(plate_array.get(before).peek());
      ;
        System.out.println("plate "+ plate_array.get(before).pop()+" move:"+s[before]+"-------->"+s[after]);
        return true;
    }

    public static void hanoi_tower(){
        int count=0;
        if(PLATE_COUNT%2==1){
            s[1]='C';
            s[2]='B';
        }
        while (true){
            ++count;
            move((count - 1) % 3, (count) % 3 );
            if (!move((count - 1) % 3 , (count + 1) % 3 )&&!move((count + 1) % 3, (count - 1) % 3 ))
                break;


        }
    }

    public static void main(String[] args){
        if(plate.size()>0){
            plate.clear();
        }
        for(int i=PLATE_COUNT;i>0;i--){
            plate.push(i);
        }
        System.out.println("遞歸求移動漢諾塔的步驟:");
        hanoi_tower(PLATE_COUNT,'A','B','C');
        System.out.println("總共移動"+count+"次");
        System.out.println("*********************");
        System.out.println("非遞歸求移動漢諾塔的步驟");
        for(int i=0;i<3;i++){
            plate_array.add(new Stack<Integer>());
        }
        for(int i=PLATE_COUNT;i>0;i--){
            plate_array.get(0).push(i);
        }
        hanoi_tower();

    }

}

複製代碼

代碼運行結果以下:ui

遞歸求移動漢諾塔的步驟:
plate 1 move:A-------->C
plate 2 move:A-------->B
plate 1 move:C-------->B
plate 3 move:A-------->C
plate 1 move:B-------->A
plate 2 move:B-------->C
plate 1 move:A-------->C
總共移動7次
*********************
非遞歸求移動漢諾塔的步驟
plate 1 move:A-------->C
plate 2 move:A-------->B
plate 1 move:C-------->B
plate 3 move:A-------->C
plate 1 move:B-------->A
plate 2 move:B-------->C
plate 1 move:A-------->C

複製代碼
參考連接:

blog.csdn.net/qq_19446965…
blog.csdn.net/yhf_naive/a…
spa

轉載請註明出處,謝謝合做!若是喜歡此文章不妨點個贊,也能夠來下關注。.net

相關文章
相關標籤/搜索