算法基礎三:分治算法---漢諾塔問題
一、遞歸與分治
很多有用的算法是遞歸(recursive)結構的:為了解決一個給定的問題,遞歸地調用自身一次或者多次來解決關系密切的若干個子問題。這樣的算法通常遵循分治(divide and conque)方法:它們將問題分解成若干個與原問題相似而規模較小的子問題,遞歸地解決這些子問題,然后把子問題的解合並成原問題的一個解。
分治范式在每一層遞歸包括三個步驟:
- 分解:將問題分解成若干個子問題
- 治理:遞歸地解決各子問題。不過若子問題的規模足夠小,就直接解決。
- 合並:將子問題的解合並成原問題的一個解
二、漢諾塔問題與遞歸
1、算法的描述與分析
n個大小不同的圓盤(中心有孔,按照尺寸從小到大一次編號為1,2,3,...,n)按尺寸大小(大在下,小在上)疊放在3根桿(編號為A、B和C)的A號桿上,每次移動一個盤,將這n個盤從A號桿移動到C號桿上。移動的過程中不允許大盤疊放在小盤上。要求以最少的移動步驟達到移動目標。

2、偽代碼描述

3、解題步驟分析:
第一步:
把n-1個模塊 從塔1移動到塔2
把第n個模塊 從塔1移動到塔3
第二部:
把n-1個模塊 從塔2移動到塔3
三、代碼實現
1、Java語言實現
public class Hanoi {
static int m =0;//標記移動次數
//實現移動的函數
public static void move(int disks,char N,char M)
{
System.out.println("第" + (++m) +" 次移動 : " +" 把 "+ disks+" 號圓盤從 " + N +" ->移到-> " + M);
}
//遞歸實現漢諾塔的函數
public static int hanoi(int n,char A,char B,char C)
{
if(n == 1)//圓盤只有一個時,只需將其從A塔移到C塔
Hanoi.move(1, A, C);//將編b號為1的圓盤從A移到C
else
{//否則
hanoi(n - 1, A, C, B);//遞歸,把A塔上編號1~n-1的圓盤移到B上,以C為輔助塔
Hanoi.move(n, A, C);//把A塔上編號為n的圓盤移到C上
hanoi(n - 1, B, A, C);//第二步:遞歸,把B塔上編號1~n-1的圓盤移到C上,以A為輔助塔
}
return m;
}
}
2、測試
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner imput = new Scanner(System.in);
char A = 'A';
char B = 'B';
char C = 'C';
System.out.println("******************************************************************************************");
System.out.println("這是漢諾塔問題(把A塔上編號從小號到大號的圓盤從A塔通過B輔助塔移動到C塔上去");
System.out.println("******************************************************************************************");
System.out.print("請輸入圓盤的個數:");
int disks = imput.nextInt();
int m = Hanoi.hanoi(disks, A, B, C);
System.out.println(">>移動了" + m + "次,把A上的圓盤都移動到了C上");
imput.close();
}
}
四、遞歸與分治感悟
通過漢諾塔問題,學習到了把一個大問題分解成若干個小問題,最終分解成最簡單的一個問題,也就是遞歸地結束點。
