算法思维基础(1)递归

1.递归:如何利用递归求解汉诺塔问题?
不管是数据结构还是算法思维,它们的目标都是降低时间复杂度
数据结构是从数据组织形式的角度达成这个目标
算法思维则是从数据处理的思路上去达成这个目标
1.1什么是递归
递归是指在函数的定义中使用函数自身的方法
递归有两层含义:
递归问题必须可以分解为若干个规模较小、与原问题形式相同的子问题
并且这些子问题可以用完全相同的解题思路来解决
递归问题的演化过程是一个对原问题从大到小进行拆解的过程,并且会有一个明确的终点(临界点)
最后从这个临界点开始,把小问题的答案按照原路返回,原问题便得以解决
递归的基本思想是把规模大的问题转化为规模小的相同的子问题来解决
在函数实现时,大问题的解决方法和小问题的解决方法是同一个方法
解决问题的函数必须有明确的结束条件,否则就会导致无限递归的情况
递归的实现包含了两个部分:
递归主体
终止条件
1.2递归的算法思想
递归的数学模型其实就是数学归纳法
一个常见的题目是:证明当n等于任意一个自然数时某命题成立
当采用数学归纳法时,证明分为以下两个步骤:
1.证明当n=1时成立
2.假设n=m时命题成立,那么尝试推导出在n=m+1时命题也成立
当采用递归算法解决问题时,需要围绕这2个步骤去做文章:
1.当面对一个大规模问题时,如何把它分解为几个小规模的同样的问题
2.当把问题通过多轮分解后,最终的结果,也就是终止条件如何定义
当一个问题同时满足以下2个条件时,就可以使用递归的方法求解:
1.可以拆解为除了数据规模以外,求解思路完全相同的子问题
2.存在终止条件
对树中的任意结点
1.中序遍历它的左子树
2.打印这个结点
3.中序遍历它的右子树
当某个结点没有左子树和右子树时,则直接打印结点,完成终止。由此可见,树的中序遍历完全满足递归的两个条件,因此可以递归实现。每次递归都调用了一次基础代码,代码如下

// 中序遍历

public static void inOrderTraverse(Node node) {

	if (node == null)

		return;

	inOrderTraverse(node.left);

	System.out.print(node.data + " ");

	inOrderTraverse(node.right);

}```
以上就是递归算法的思想。写出递归代码的关键在于,写出递推公式和找出终止条件。即需要找到将大问题分解成小问题的规律,并基于此写出递推公式;然后找出终止条件。
1.3递归的案例
汉诺塔问题是源于印度一个古老传说的益智玩具。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着 64 片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上,并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
我们可以把这个问题抽象为一个数学问题。如下图所示,从左到右有 x、y、z 三根柱子,其中 x 柱子上面有从小叠到大的 n 个圆盘。现要求将 x 柱子上的圆盘移到 z 柱子上去。要求是,每次只能移动一个盘子,且大盘子不能被放在小盘子上面。求移动的步骤。
我们的原问题是,把从小到大的 n 个盘子,从 x 移动到 z。
我们可以将这个大问题拆解为以下 3 个小问题:
把从小到大的 n-1 个盘子,从 x 移动到 y;
接着把最大的一个盘子,从 x 移动到 z;
再把从小到大的 n-1 个盘子,从 y 移动到 z。
首先,我们来判断它是否满足递归的第一个条件。 其中,第 1 和第 3 个问题就是汉诺塔问题。这样我们就完成了一次把大问题缩小为完全一样的小规模问题。我们已经定义好了递归体,也就是满足来递归的第一个条件。	
随着递归体不断缩小范围,汉诺塔问题由原来“移动从小到大的 n 个盘子”,缩小为“移动从小到大的 n-1 个盘子”,直到缩小为“移动从小到大的 1 个盘子”。移动从小到大的 1 个盘子,就是移动最小的那个盘子。根据规则可以发现,最小的盘子是可以自由移动的。因此,递归的第二个条件,终止条件,也是满足的。
经过仔细分析可见,汉诺塔问题是完全可以用递归实现的。我们定义汉诺塔的递归函数为 hanio()。这个函数的输入参数包括了:
3 根柱子的标记 x、y、z;
待移动的盘子数量 n。
具体代码如下所示,在代码中,hanio(n, x, y, z),代表了把 n 个盘子由 x 移动到 z。根据分析,我们知道递归体包含 3 个步骤:
把从小到大的 n-1 个盘子从 x 移动到 y,那么代码就是 hanio(n-1, x, z, y);
再把最大的一个盘子从 x 移动到 z,那么直接完成一次移动的动作就可以了;
再把从小到大的 n-1 个盘子从 y 移动到 z,那么代码就是 hanio(n-1, y, x, z)。对于终止条件则需要判断 n 的大小。如果 n 等于 1,那么同样直接移动就可以了

```java
public static void main(String[] args) {

    String x = "x";

    String y = "y";

    String z = "z";

    hanio(3, x, y, z);

}

public void hanio(int n, String x, String y, String z) {

    if (n < 1) {

        System.out.println("汉诺塔的层数不能小于1");

    } else if (n == 1) {

        System.out.println("移动: " + x + " -> " + z);

        return;

    } else {

        hanio(n - 1, x, z, y);

        System.out.println("移动: " + x + " -> " + z);

        hanio(n - 1, y, x, z);

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值