算法基础三:分治算法---汉诺塔问题
一、递归与分治
很多有用的算法是递归(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();
}
}
四、递归与分治感悟
通过汉诺塔问题,学习到了把一个大问题分解成若干个小问题,最终分解成最简单的一个问题,也就是递归地结束点。