zoukankan      html  css  js  c++  java
  • 递归函数两种方式的区别

    概述

    递归函数都不陌生,比如计算n的阶乘:

    function f($n){
        if($n <= 1) return 1;
        return $n * f($n-1);
    }

    当然,有人可能会这么写:

    function f($n, $result){
        if($n <= 1) return $result;
        return f($n-1, $n*$result);
    }

    上面两种方式看着好像没什么区别,但是在cpu眼中,可就不一样了。

    分析

    函数在调用的时候会开辟一块函数栈,用来保存函数的局部变量、参数、上一个栈的指针、返回值等信息,当函数调用结束后会销毁。递归函数会一直递归下去,上层的函数栈一直不会销毁,知道递归结束,全部退出。

    举个栗子,当调用f(3)的时候,对于上面的第一种情况,函数栈大概长这样(仅保留参数和返回值,忽略其他内容):

    文字描述就是:

    f(1)=1

    f(2)=2*f(1)=2*1=2

    f(3)=3*f(2)=3*2=6

    f(4)=4*f(3)=4*6=24

    也就是每一次调用,都会保存本次的变量n以及递归调用的返回值,这就会导致如果递归的太神,就会开辟太多的内存。

    如果使用第二种写法,会有什么不同么?

    套用刚才的分析,先用文字描述一下:

    f(4, 1)=f(3, 4*1)=f(2, 3*4)=f(1, 2*12)=24

    有没有发现区别,区别就是,前一种写法要保存一个局部变量n,而后一种写法,都写到下一个方法的参数中了。也就是说,第二种方式,可以直接返回下层方法,不需要退回去了。当然,cpu发现这种情况,会复用函数栈,也就是说,函数栈大概是这么个情况:

    看着好像也没啥区别,但是!因为可以直接返回,上图的四个栈使用的都是同一个栈。


    当递归返回的是递归调用,并且讲调用直接返回,没有参与运算等,就会被这样优化,复用栈。

  • 相关阅读:
    互联网秒杀设计
    生产者消费者模式实现
    Ping CAP CTO、Codis作者谈redis分布式解决方案和分布式KV存储
    VIM使用学习笔记 : 按键说明
    Cookie的有效访问路径
    简单的Cookie记录浏览记录案例
    认识Cookie和状态管理
    Java异常
    Java接口基础
    String常用方法
  • 原文地址:https://www.cnblogs.com/hujingnb/p/11823555.html
Copyright © 2011-2022 走看看