递归和调用栈

递归和调用栈

本节学习如何将问题分为基线条件和递归条件

递归体现在代码中就是调用自己,除非符合跳出条件结束程序或返回

基线条件和递归条件

举例,代码实现简单倒计时

 private static void countdown(int i) throws InterruptedException{
        System.out.println(i);
        if (i <= 0) {
            //基线条件
            return;
        }else{
            //递归条件
            Thread.sleep(1000);
            countdown(--i);
        }
    }

每个正常的递归函数都有两个部分:基线条件(base case)和递归条件(recursive case)。

基线条件是让函数不再调用自己,从而避免无限循环的条件。

递归条件是让函数继续调用自己的条件。

栈(stack)

栈的基本概念

递归涉及一个叫做**调用栈(call stack)非常重要的概念**。

是常用的数据结构,只涉及压入、弹出两种操作。进出顺序是先进后出。栈分为栈底和栈顶,栈底无法进出元素,只有栈顶能进出,就像一个弹匣一样,先压入的子弹后打出,最后压入的子弹最先打出。

调用栈

在有些地方也叫调用堆栈,debug打断点时常常会见到这个东西。

调用栈用于存放以下东西:

  • 函数结束后应当返回的地址
  • 本地变量:子程序的变量可存入调用栈,以达到不同子程序间变量分离
  • 参数传递:如果寄存器不足以容纳子程序的参数,可以在调用栈上存入参数。
  • 环境传递:有些语言(如PascalAda)支持“多层子程序”,即子程序中可以利用主程序的本地变量。这些变量可以通过调用栈传入子程序。

假设有函数如下

public class CallStackDemo {
    
    public static void main(String[] args) {
        int i = 0;
        i = calFirst(i);
        System.out.println(i);
    }

    public static int calFirst(int i){
        i = calTwice(i);
        return i += 1;
    }

    public static int calTwice(int i){
        i = calThird(i);
        return i += 2;
    }

    public static int calThird(int i){  
        return i += 3;
    }

}

上述代码在可见内共有五个函数,分别是

  1. main函数

  2. calFirst()函数

  3. calTwice()函数

  4. calThird()函数

  5. System.out.println()函数

当调用main函数时,计算机为该函数分配一块内存,并保存main函数中的变量到该内存中。

调用calFirst()函数时也是一样,计算机为该函数分配一块内存,并保存其中的变量 i

调用calTwice()函数时也是一样,计算机为该函数分配一块内存,并保存其中的变量 i

……

计算机使用一个栈保存这些内存块,其中第二个内存块位于第一个内存块上,函数调用完毕返回后,内存块弹出,如下图变化

在这里插入图片描述

calThird()是最先被执行,执行完毕后,calThird内存块被弹出,等待内存回收,程序返回到calTwice,直到calFirst被执行完毕,返回到main函数中。

此时在栈顶,也就是main函数的顶部添加了System.out.println函数所属的内存块,执行完打印函数后返回到main函数,随即main函数也执行完毕,等待内存回收。

这个栈用于保存多个函数的内存块等,体现调用关系,叫做调用栈

在函数A中调用另一个函数时,函数A暂停并处于未完成状态,改函数所有变量值都还在内存中。

总结

栈的每一个内存块一定要保存自己被弹出时需要返回到的内存地址。

先加载完成的内存块所属的子程序会最后执行,最后加载最先执行。

每个递归函数都有基线条件和递归条件两个条件。

所有函数的调用都要进入调用栈。

调用栈很长时,如递归调用栈,将占用极大的内存,此时选择有如下两个:

  • 重新编写代码,转而使用循环等方式。
  • 使用尾递归。这是一个高级递归。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值