• python递归基础


    4.2 何谓递归


      递归是解决问题的一种方法,它将问题不断地分成更小的子问题,直到子问题可以用普通的方法解决。通常

    情况下,递归会使用一个不停调用自己的函数。尽管表面上看起来很普通,但是递归可以帮助我们写出非常优雅

    的解决方案。对于某些问题,如果不用递归,就很难解决。

    4.2.1 计算一列数之和


      我们从一个简单的问题开始学习递归。即使不用递归,我们也知道如何解决这个问题。假设需要计算数字列

    表[1, 3, 5, 7, 9]的和。代码清单4-1展示了如何通过循环函数来计算结果。这个函数使用初始值为0的累加变量

    theSum,通过把列表中的数加到该变量中来计算所有数的和。

      代码清单4-1 循环求和函数

    def listsum(numlist):
        thesum = 0
        for i in numlist:
            thesum = thesum + i
        
        return thesum


      假设暂时没有while循环和for循环。应该如何计算结果呢?如果你是数学家,就会记得加法是接受两个参数

    (一对数)的函数。将问题从求一列数之和重新定义成求数字对之和,可以将数字列表重写成完全括号表达式,

    例如((((1 + 3) + 5) + 7) + 9)。该表达式还有另一种添加括号的方式,即(1 + (3 + (5 + (7 + 9))))。注意,最内

    层的括号对(7 + 9)不用循环或者其他特殊语法结构就能直接求解。事实上,可以使用下面的简化步骤来求总和。

        总和 = (1 + (3 + (5 + (7 + 9))))

        总和 = (1 + (3 + (5 + 16)))

        总和 = (1 + (3 + 21))

        总和 = (1 + 24)

        总和 = 25

      如何将上述想法转换成Python程序呢?让我们用Python列表来重新表述求和问题。数字列表numList的总

    和等于列表中的第一个元素(numList[0])加上其余元素(numList[1:])之和。可以用函数的形式来表述这个

    定义。返回列表中的第一个元素,则返回其余元素。用Python可以轻松地实现这个等式,如代码清单4-2所示。

      代码清单4-2 递归求和函数

    def listsum(numlist):
        if len(numlist) == 1:
    
            return numlist[0]
    
        else:
    
            return numlist[0] + listsum(numlist[1:])
    


      在这一段代码中,有两个重要的思想值得探讨。首先,第2行检查列表是否只包含一个元素。这个检查非常

    重要,同时也是该函数的退出语句。对于长度为1的列表,其元素之和就是列表中的数。其次,listsum函数在第

    5行调用了自己!这就是我们将listsum称为递归函数的原因——递归函数会调用自己。

      图4-1展示了在求解[1, 3, 5, 7, 9]之和时的一系列递归调用。我们需要将这一系列调用看作一系列简化操作。

    每一次递归调用都是在解决一个更小的问题,如此进行下去,直到问题本身不能再简化为止。


                    图4-1 求和过程中的递归调用

      当问题无法再简化时,我们开始拼接所有子问题的答案,以此解决最初的问题。图4-2展示了listsum函数

    在返回一系列调用的结果时进行的加法操作。当它返回到顶层时,就有了最终答案。



                    图4-2 求和过程中的一系列返回操作


    4.2.2 递归三原则

    正如阿西莫夫提出的机器人三原则一样,所有的递归算法都要遵守三个重要的原则:

      (1) 递归算法必须有基本情况;

      (2) 递归算法必须改变其状态并向基本情况靠近;

      (3) 递归算法必须递归地调用自己。

      让我们来看看listsum算法是如何遵守上述原则的。基本情况是指使算法停止递归的条件,这通常是小到足

    以直接解决的问题。listsum算法的基本情况就是列表的长度为1。

      为了遵守第二条原则,必须设法改变算法的状态,从而使其向基本情况靠近。改变状态是指修改算法所用

    的某些数据,这通常意味着代表问题的数据以某种方式变得更小。listsum算法的主数据结构是一个列表,因此

    必须改变该列表的状态。由于基本情况是列表的长度为1,因此向基本情况靠近的做法自然就是缩短列表。这正

    是代码清单4-2的第5行所做的,即在一个更短的列表上调用listsum。

      最后一条原则是递归算法必须对自身进行调用,这正是递归的定义。对于很多新手程序员来说,递归是令

    他们颇感困惑的概念。新手程序员知道如何将一个大问题分解成众多小问题,并通过编写函数来解决每一个小

    问题。然而,递归似乎让他们落入怪圈:有一个需要用函数来解决的问题,但是这个函数通过调用自己来解决

    问题。其实,递归的逻辑并不是循环,而是将问题分解成更小、更容易解决的子问题。

  • 相关阅读:
    一些至理名言
    移除快捷方式上面那个丑陋的小箭头
    一些浏览器插件
    yahoo给出的关于网站优化的建议
    javascript 事件流
    关于mongodb的一些笔记
    WebStorm
    给go添加各种package
    工具类 util.Date 日期类
    几种简单排序算法
  • 原文地址:https://www.cnblogs.com/mtfan01/p/14813610.html
Copyright © 2020-2023  润新知