递归:如何利用递归求解汉诺塔问题?
Posted liuxia912
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归:如何利用递归求解汉诺塔问题?相关的知识,希望对你有一定的参考价值。
【什么是递归】
在数学与计算机科学中,递归 (Recursion))是指在函数的定义中使用函数自身的方法,直观上来看,就是某个函数自己调用自己。
? ?
递归有两层含义:
递归问题必须可以分解为若干个规模较小、与原问题形式相同的子问题。并且这些子问题可以用完全相同的解题思路来解决;
? ?
递归问题的演化过程是一个对原问题从大到小进行拆解的过程,并且会有一个明确的终点(临界点)。
一旦原问题到达了这个临界点,就不用再往更小的问题上拆解了。最后,从这个临界点开始,把小问题的答案按照原路返回,原问题便得以解决。
? ?
简而言之,递归的基本思想就是把规模大的问题转化为规模小的相同的子问题来解决。 在函数实现时,因为大问题和小问题是一样的问题,因此大问题的解决方法和小问题的解决方法也是同一个方法。这就产生了函数调用它自身的情况,这也正是递归的定义所在。
? ?
格外重要的是,这个解决问题的函数必须有明确的结束条件,否则就会导致无限递归的情况。
总结起来,递归的实现包含了两个部分,一个是递归主体,另一个是终止条件。
? ?
【汉诺塔问题】
汉诺塔问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着 64 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上,并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
? ?
我们可以把这个问题抽象为一个数学问题。如下图所示,从左到右有 x、y、z 三根柱子,其中 x 柱子上面有从小叠到大的 n 个圆盘。现要求将 x 柱子上的圆盘移到 z 柱子上去。要求是,每次只能移动一个盘子,且大盘子不能被放在小盘子上面。求移动的步骤。
? ?
? ?
我们来分析一下这个问题。这是一个大规模的复杂问题,如果要采用递归方法去解决的话,就要先把问题化简。
? ?
我们的原问题是,把从小到大的 n 个盘子,从 x 移动到 z。
? ?
我们可以将这个大问题拆解为以下 3 个小问题:
把从小到大的 n-1 个盘子,从 x 移动到 y;
接着把最大的一个盘子,从 x 移动到 z;
再把从小到大的 n-1 个盘子,从 y 移动到 z。
代码如下:
public static void main(String[] args) { String start = "x"; String temp = "y"; String end = "z"; hanio(6, start, temp, end); } ? ? public static void hanio(int n, String start, String temp, String end) { if (n < 1) { System.out.println("汉诺塔的层数不能小于1"); } else if (n == 1) { System.out.println("移动: " + start + " -> " + end); return; } else { hanio(n - 1, start, end, temp); System.out.println("移动: " + start + " -> " + end); hanio(n - 1, temp, start, end); } } |
? ?
抛开用于处理输入异常的代码部分不谈,它的代码包含了 2 个部分:
终止条件,即如何处理小规模的问题,实现的代码量一定是很少的;
递归体,即大问题向小问题分解的过程,实现的代码量也不会太多。
? ?
因此,一个复杂问题的递归实现,通常代码量都不会很多。
?
【总结】
递归的核心思想是把规模大的问题转化为规模小的相似的子问题来解决。
? ?
在函数实现时,因为解决大问题的方法和解决小问题的方法往往是同一个方法,所以就产生了函数调用它自身的情况。
另外这个解决问题的函数必须有明显的结束条件,这样就不会产生无限递归的情况了。
以上是关于递归:如何利用递归求解汉诺塔问题?的主要内容,如果未能解决你的问题,请参考以下文章