递归与迭代

什么是递归

任何调用自身的函数称为递归

为什么用递归

递归是从数学领域借鉴过来的一种有用的技术,递归代码通常比迭代代码更加简洁易懂。一般来说,在编译和解释时,循环会转化为递归函数。当任务能够被相似的子任务定义时,采用递归处理十分有效。例如:排序、搜索、和遍历等问题往往有简洁的递归解决方案。

以阶乘为例

//计算一个正整数的阶乘
public static int Fact(int n){
    //基本情形:当参数为0或者为1时,返回1
    if(n == 1)
        return 1;
    else if(n == 0)
        return 1;
    else 
        return n*Fact(n-1);
}
public static void main(String[] args) {
    System.out.print(Fact(5));
    // 120
}

递归和内存(可视化)

每次递归调用都在内存中生成一个新的函数副本(实际上仅仅是一些相关的变量)。一旦函数结束(即返回某些数据),该返回函数的副本就从内存中删除。递归方案看起来简单,但是可视化和跟踪递归过程需要花费时间。为了更好地理解递归过程,考虑下面的例子。

int Print(int n){
    if(n == 0)
        return 0;
    else {
        System.out.println(n);
        return Print(n-1);
    }
}

在这个例子中,假设当参数n = 4时调用Print函数,内存分配的可视化过程如下图所示。
图1

递归与迭代

在讨论递归时,一个基本问题是递归与迭代,各种方法更好?这个问题的答案,取决于我们想做什么。递归方法通过类似镜像的方式来解决问题。当问题没有明显的答案时,递归方法通过简化问题来解决它。但是,每次递归调用都会增加开销(栈需要开销空间)

递归
  • 当到达基本情形时,递归终止
  • 每次递归调用都需要额外的空间用于栈帧(内存)开销
  • 如果出现无穷递归,程序可能耗尽内存,并出现栈溢出
  • 某些问题采取递归方法更容易解决
迭代
  • 当循环条件为假时,迭代终止
  • 每次迭代不需要任何额外的空间开销
  • 由于没有额外开销,所以若出现死循环,则程序会一直循环执行
  • 采用迭代求解问题可能没有递归解决方案那样显而易见

递归说明

  • 递归算法有两种情形:递归情形和基本情形(结束情况)
  • 每个递归函数必须终止于基本情形
  • 通常,迭代解决方案比递归解决方案更加有效(因为后者有函数调用的开销)
  • 一个递归算法可以通过使用栈代替递归函数的方式来实现,但通常是得不偿失的。这意味着任何能用递归求解的问题也能用迭代来求解。
  • 对于某些问题,没有明显的迭代求解算法。
  • 有些问题非常适合用递归来求解,而有些则不合适。

递归算法的经典用例

  • 斐波那契数列、阶乘
  • 归并排序、快速排序
  • 二分查找
  • 树的遍历和许多树问题:中序遍历、前序遍历、后续遍历
  • 图的遍历:深度优先搜索、广度优先搜索
  • 动态规划例子
  • 分治算法
  • 汉诺塔
  • 回溯算法

递归相关问题

1.汉诺塔谜题

汉诺塔是一个数学谜题。有3根柱子(或木柱、塔)和一些可以在柱子之间来回移动的不同大小的圆盘。开始时,所有的圆盘按照从小到大的次序自上而下叠放在一根柱子上,形成一个圆锥结构。现在要求把整叠圆盘移动到另一根柱子上,移动时要遵守下面的规则:
- 每次只能移动一个圆盘
- 每次移动,只能移动柱子最上面的一个圆盘到另一根柱子(这根柱子上有可能已有圆盘)
- 任何时候不能出现 大圆盘在小圆盘的上方的情况

算法:
  • 将源柱最上面的n-1个圆盘移到辅助柱。
  • 将第n个圆盘从源柱 移到目标住
  • 将辅助柱的n-1个圆盘移到目的柱
  • 源柱最上面的n-1个圆盘移动到辅助柱有可以认为 是一个新问题,并且可以用同样的方式解决。一旦能解决了只有3个圆盘的汉诺塔问题,那么这个算法可以求解任意数量圆盘的汉诺塔问题
public static void TowerOfHanoi(int n,char fromA,char toB,char auxC){
    if(n == 1){
        System.out.println(n+"--"+fromA +" to peg "+ toB);
        return;
    }
    TowerOfHanoi(n-1,fromA,auxC,toB);

    System.out.println(n+"--"+fromA + " to peg " + toB);

    TowerOfHanoi(n-1,auxC,toB,fromA);
}
public static void main(String[] args) {
    char A = 97;
    char B = 98;
    char C = 99;
    TowerOfHanoi(4,A,B,C);
    /**
        1--a to peg c
        2--a to peg b
        1--c to peg b
        3--a to peg c
        1--b to peg a
        2--b to peg c
        1--a to peg c
        4--a to peg b
        1--c to peg b
        2--c to peg a
        1--b to peg a
        3--c to peg b
        1--a to peg c
        2--a to peg b
        1--c to peg b
    **/
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CiBa-YAO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值