赞
踩
(可忽略)背景:目前,网上有很多关于汉诺塔求解的博文,我看了一些,感觉大致相同。首先都是圆盘移动的规律讲解了一下,然后贴上了解题代码。对递归的本质,没有进行深入的探究,可能也能解决当前的汉诺塔问题,但是给你一个新的递归类问题去解决,还是不行。在学习了imooc刘老师的课程后,对递归有了更清晰的认识,因此写此博文,总结递归类型问题的求解方法。希望看的人也可以有所收获,谢谢。
此部分通过一个简单的案例:数组求和。来分析递归问题的求解过程,和递归函数一般的组成部分 (对递归很熟可以忽略,建议看)。
原问题:求解数组arr[0…n-1]中从索引0开始到索引n-1所有元素的和,即Sum(arr[0…n-1]);
将原问题转化为规模更小的同一问题,求从索引1开始到索引n-1所有元素的和,即Sum(arr[1…n-1])。然后用规模更小的问题的解去构建原问题的解,即
arr[0] + Sum(arr[1…n-1])。
上述过程一直重复,更小的同一问题,转化为更更小的同一问题,用更更小的同一问题去构建更小的同一问题的解。直到该问题不能被转化或分解成更小的问题,这里我们把该问题称为最基本的问题,即Sum([])
(总结)从上面递归问题的求解过程,我们可以得出解决递归问题的一般方法:找到最基本问题并给出基本问题的解;将原问题转换(或分解)成规模更小的同一问题,用规模更小的同一问题,去构建原问题的解。
注意函数的“宏观”语义。即函数本身的功能,不要去过多的关注代码的执行过程!
以上都是刘老师相关课程的学习总结。下面正式开始用递归方式解决汉诺塔问题。
A 代表源柱子,B代表辅助柱子,C代表目标柱子
问题描述参考链接
从图中可以看出,原问题被分解成了三个更小的同一问题。
第一个更小的同一问题作用:把除最后一个圆盘之上的所有圆盘,从A上,借助C,移动到B上
第二个更小的同一问题作用:把最后一个圆盘,从A上,借助B,移动到C上
第三个更小的同一问题作用:把所有圆盘,从B上,借助A,移动到C上
至此,我们把原问题分解成了三个更小的同一问题,并利用三个更小的同一问题的解(更小的同一问题的分解过程和原问题的分解过程相同)构建出了原问题的解。
最基本的问题(即该问题不同被分解成更小的同一问题)显然是一个圆盘的移动;
(1)到(7)的过程即实际解题时的移动过程,可以自己测试下。
/** * 把source上的n个圆盘,借助assist,移动到destination上 * @param source 源 * @param assist 辅助 * @param destination 目标 * @param n 移动的数量 */ public static void move( char source, char assist, char destination, int n){ // 最基本问题的解 if(n == 1){ System.out.println(source + "--->" + destination); return; } // 把原问题转化为更小的同一问题,然后用更小的同一问题的解构建原问题的解 move(source, destination, assist, n - 1); move(source, assist, destination, 1); move(assist, source, destination, n - 1); } // 测试函数 public static void main(String[] args) { move('A', 'B', 'C', 3); }
执行结果如下,和我们在第二部分分析的过程相同。
/** * 把source上的count个圆盘,借助assist,移动到destination上 * @param source 源 * @param assist 辅助 * @param destination 目标 * @param n 移动的数量 * @depth 递归深度,表示当前执行的递归函数位于那一层 */ public static void move( char source, char assist, char destination, int n, int depth){ String depthString = generateDepthString(depth); // 首先,说明函数的执行目标 System.out.print(depthString); System.out.println(String.format("Call: move %d disk(s) from %c to %c with the help of %c.", n, source, destination, assist)); // 最基本问题的解 if(n == 1){ // 每一步的作用 System.out.print(depthString); System.out.println(source + "--->" + destination); return; } // 把原问题转化为更小的同一问题,然后用更小的同一问题的解构建原问题的解 // 每一步的作用 System.out.print(depthString); System.out.println(String.format("Call: move %d disk(s) from %c to %c with the help of %c." , n - 1, source, assist, destination)); move(source, destination, assist, n - 1, depth + 1); System.out.print(depthString); System.out.println(String.format("Call: move %d disk(s) from %c to %c with the help of %c." , 1, source, destination, assist)); move(source, assist, destination, 1, depth + 1); System.out.print(depthString); System.out.println(String.format("Call: move %d disk(s) from %c to %c with the help of %c." , n - 1, assist, destination, source)); move(assist, source, destination, n - 1, depth + 1); } /** * 生成代表递归函数深度的字符串,第一层即 "--". * @param depth * @return */ private static String generateDepthString(int depth){ StringBuilder res = new StringBuilder(); for(int i = 0; i < depth; i ++){ res.append("--"); } return res.toString(); } // 测试函数 public static void main(String[] args) { move('A', 'B', 'C', 3, 0); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。