博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
递 归
阅读量:6261 次
发布时间:2019-06-22

本文共 2291 字,大约阅读时间需要 7 分钟。

递归的定义:在数学和计算机科学中,递归是指在函数的定义中调用函数自身的方法。

递归举例:斐波那契数列。

>>> def fib(n):...     '''This is Fibonacci by Recursion'''...     if n == 0:    # 函数结束的条件...         return 0...     elif n == 1:...         return 1...     else:...         return fib(n-1) + fib(n-2)    # 递归,定义函数的内部调用函数自身...>>> fib(10)55

  从上面的计算过程可以看出,每个递归的过程都是向着最初的已知条件(结束条件)方向挺近一步,直到通过这个最底层的条件得到结果,然后再一层一层向上回馈(返回)计算结果。

       将上面的例子优化:

>>> m = {0:0, 1:1}    # n=1和n=0的值已知,直接定义出来,省去每次的多个判断>>> def fib(n):...     if not n in m:...         m[n] = fib(n-1) + fib(n-2)...     return m[n]...>>> fib(10)55

  递归的要素:

              结束条件:满足条件时,函数调用结束,直接返回一个值,即有一个明确的递归结束条件,称为递归出口。

              递归调用:包含一个或多个调用,这些调用旨在解决问题的一部分。

         这里的关键是,通过一次次的分解问题,将问题分解为较小的部分,最终分解到结束条件。

  递归的回溯与递推:

    递推:像上边递归实现所拆解,递归每一次都是基于上一次进行下一次的执行,这叫递推;

    回溯:则是在遇到终止条件,则从最后往回返,一级一级的把值返回,这叫回溯。

>>> lst =[1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15,[16,[17,]],19]]]]]]]>>> def search(lst):...     for item in lst:...         if type(item) is list:...             search(item)...         else:    # 递归调用结束条件...             print(item, end=' ')    ...>>> search(lst)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 19

  深刻理解:每次递归调用函数时,都将为这个递归调用的函数创建一个新的命名空间。各自的命名空间是相互独立的,每个递归函数在各自的命名空间内生存并依次按顺序执行;当执行到结束条件时,从结束的位置开始向前一次次的反馈(返回)并继续执行每个命名空间内剩余的部分。关键在于每次递归时都会创建各自相互独立的命名空间。

  两个经典案例:阶乘和幂

    阶乘:1的阶乘为1;

            对于大于1的数字n,其阶乘为n-1的阶乘再乘以n。

>>> def func(n):...     if n == 1:...         return 1...     return n * func(n-1)...>>> func(5)120

  幂:对于任何数字x,power(x, 0)都为1;

    n>0时,power(x, n)为power(x, n-1)与x的乘积。

>>> def func(n, m):...     if m == 0:...         return 1...     if m < 0:...         return (1/n) * func(n, m+1)...     else:...         return n * func(n, m-1)...>>> func(3, 3)27>>> func(3, 1)3>>> func(3, 0)1>>> func(3, -1)0.3333333333333333>>> func(3, -2)0.1111111111111111>>> func(3, -3)0.037037037037037035

递归的特点:

         必须有一个明确的结束条件;

         每次进入更深一层递归时,问题的规模相比上次递归都应有所减少;

         递归效率不高,递归层次太多,会导致栈溢出。在计算机中,函数调用是通过栈(stack)这种数据结构实现的。每当进入一个函数调用,栈就会增加一层栈帧;每当函数返回,栈就会减少一层栈帧。由于栈的大小不是无限的,所以递归调用次数过多,会导致栈溢出。

递归的优缺点:

  优点:

    递归使代码看起来更加整洁、优雅;

    可以用递归将复杂任务分解成更简单的子问题;

    使用递归比使用一些嵌套迭代更容易。

  缺点:

    递归的逻辑很难调试、跟进;

    递归调用的代价高昂(效率低),因为占用了大量的内存和时间。

  注意:Python3默认递归的深度不能超过997层。

 

  尾递归调用优化:

    在函数的最后一步进入递归调用。这样每层函数的调用就直接结束了,不会去等待下一次递归调用的返回值,这样每次执行完毕进入下一次后,就不会占用内存去保存当前层的状态,节省内存空间。

 

转载于:https://www.cnblogs.com/wgbo/p/9670842.html

你可能感兴趣的文章
[Elasticsearch]Elasticsearch+kibana+marvel安装
查看>>
《Kotlin 程序设计》第四章 Kotlin 语法基础
查看>>
开源堡垒机 Jumpserver v1.4.8 发布 , Bug 修复版本
查看>>
(十五)Java并发性和多线程-死锁
查看>>
第1章 JVM语言家族概览 《Kotin 编程思想·实战》
查看>>
spring之HttpInvoker
查看>>
我为什么“放弃”从事八年的嵌入式领域
查看>>
TypeScript基础入门 - 函数 - 重载
查看>>
【ASP】当前星期几和月份名称输出
查看>>
好看的皮囊 · 也是大自然的杰作 · 全球高质量 · 美图 · 集中营 · 美女 · 2017-08-23期...
查看>>
小二,给我来一个递增序列
查看>>
images
查看>>
又一款开源手机要来了 —— WiPhone
查看>>
爬虫入门之反反爬虫机制cookie UA与中间件(十三)
查看>>
【飞天存储服务月报】2018年6月刊
查看>>
AJAX的一些硬知识
查看>>
第208天:jQuery框架封装(一)
查看>>
JNDIUtil、DBCPUtil、C3P0Util,三种数据源的工具类的区别?
查看>>
暴风魔镜裁员了,但是VR的春天依然在路上
查看>>
Java并发编程笔记之CyclicBarrier源码分析
查看>>