zoukankan      html  css  js  c++  java
  • Day6 递归函数

    ##递归函数看的云里雾里,廖雪峰大师给出的练习题我也没搞懂,先mark下理解的,其他的后续再说……
     
    通过之前的学习已经知道,函数的内部是可以调用其他函数的,如果一个函数在内部调用自身本身,那么这个函数就是递归函数。
    定义一个计算阶乘n!的函数
        n!= 1x2x3x4x……xn,用函数来表示可以看出
        jx(n)= n! = 1 x 2 x 3 x ... x (n-1) x n = (n - 1)! x n = jx(n-1) x n
        所以jx(n)可以表示为 jx(n-1) x n ,但是当n=1时,就不行了。因此需要额外处理一下n = 1 的情况。于是 阶乘用递归方式写出来就是:
       
            def jx(n):
                if n == 1:
                    return 1
                return n * jx(n - 1)
               
    递归函数定义简单,逻辑清晰,理论上所有的递归函数都可以写成循环的方式,但是循环的逻辑不如递归清晰。
    栈溢出
        使用递归函数需要注意防止栈溢出, 函数调用是通过栈stack这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以当递归调用的次数过多时,就会导致栈溢出。
            jx(1000)
            RecursionError: maximum recursion depth exceeded in comparison
           
    尾递归优化
        解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
       
        尾递归是指在函数返回的时候,调用自身本身,并且return语句不能包含表达式。这样编译器或者解释器就可以把尾递归做优化,使递归无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
       
        例:
       
        在前面的例子里,由于  return n * jx(n - 1) 引用了乘法表达式,所以就不是尾递归。要使用尾递归方式没主要是要把每一步的乘积传入到递归函数中。
            def jx(n):
                return jx_iter(n, 1)
               
            def jx_iter(num,r1):
                if num == 1:
                    return r1
                return jx_iter(num - 1, num * r1)       #返回本次计算结果给函数本身,进入下一轮循环。
               
        尾递归调用时如果做了优化,栈不会增长,因此无论多少次调用也不会导致栈溢出。但是说这么多,在试验上面这个尾递归优化的例子时,发现python3依然会报错,因为……Python解释器也没做尾递归优化。
               
    递归函数小结:
       1.  使用递归函数的优点时逻辑简单清晰,缺点是过深的调用会导致栈溢出。
       2.  针对尾递归优化的语言可以通过尾递归防止栈溢出。尾递归事实上和循环是等价的,没有循环语句的变成语言只能通过尾递归实现循环。
       3.  python标准的解释器没有针对尾递归做优化,任何递归函数都存在栈溢出的问题。
     
     
     
  • 相关阅读:
    PostgreSQL 匹配字符串前缀
    Postgresql流复制+pgpool实现高可用
    PostgreSQL 使用Docker搭建流复制测试环境
    PostgreSQL 基于Docker的多实例安装
    PostgreSQL 基于日志的备份与还原
    PostgreSQL 利用pg_upgrade升级版本
    PostgreSQL 安装
    简单推荐系统的SQL实现
    读书笔记:集体智慧编程(1)
    Linux 光速入门
  • 原文地址:https://www.cnblogs.com/konggg/p/9049585.html
Copyright © 2011-2022 走看看