Python中递归的基础知识

Python中递归的基础知识,python,list,python-2.7,recursion,Python,List,Python 2.7,Recursion,写一个递归函数“listSum”,它接受一个整数列表并返回列表中所有整数的总和” 例如: >>>> listSum([1,3,4,5,6]) 19 我知道如何用另一种方法,但不是递归的方法 def listSum(ls): i = 0 s = 0 while i < len(ls): s = s + ls[i] i = i + 1 print s def listSum(ls): i=0 s=0 而

写一个递归函数“listSum”,它接受一个整数列表并返回列表中所有整数的总和”

例如:

>>>> listSum([1,3,4,5,6])
19
我知道如何用另一种方法,但不是递归的方法

def listSum(ls):
    i = 0
    s = 0
    while i < len(ls):
        s = s + ls[i]
        i = i + 1
    print s
def listSum(ls):
i=0
s=0
而我

我需要基本的方法来实现这一点,因为不允许使用特殊的内置函数。

对于递归函数来说,提前退出是典型的
seq
为空时为falsy(因此,当没有数字可求和时)

切片语法允许将序列传递给递归调用的函数,而无需在当前步骤中使用整数

def listSum(seq):
    if not seq:
        return 0
    return seq[0] + listSum(seq[1:])

print listSum([1,3,4,5,6])  # prints 19

当你遇到这样的问题时,试着用同样的函数来表达函数的结果

power(2, 5) = 2 * power(2, 4)
            = 2 * (2 * power(2, 3))
            = 2 * (2 * (2 * power(2, 2)))
            = 2 * (2 * (2 * (2 * power(2, 1))))
在您的例子中,您可以通过将第一个数字与使用列表中的其余元素调用相同函数的结果相加来获得结果

比如说,

listSum([1, 3, 4, 5, 6]) = 1 + listSum([3, 4, 5, 6])
                         = 1 + (3 + listSum([4, 5, 6]))
                         = 1 + (3 + (4 + listSum([5, 6])))
                         = 1 + (3 + (4 + (5 + listSum([6]))))
                         = 1 + (3 + (4 + (5 + (6 + listSum([])))))
现在,listSum([])
的结果应该是什么?应该是0。这就是递归的基本条件。当基本条件满足时,递归将结束。现在,让我们尝试实现它

>>> def power(base, exponent):
...     # Base condition, if `exponent` is lesser than or equal to 1, return `base`
...     if exponent <= 1:
...         return base
...
...     return base * power(base, exponent - 1)
... 
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
这里最重要的是,拆分列表。你可以用它来做

简单版

>>> def listSum(ls):
...     # Base condition
...     if not ls:
...         return 0
...
...     # First element + result of calling `listsum` with rest of the elements
...     return ls[0] + listSum(ls[1:])
>>> 
>>> listSum([1, 3, 4, 5, 6])
19

尾部调用递归

>>> def listSum(ls):
...     # Base condition
...     if not ls:
...         return 0
...
...     # First element + result of calling `listsum` with rest of the elements
...     return ls[0] + listSum(ls[1:])
>>> 
>>> listSum([1, 3, 4, 5, 6])
19
一旦您了解了上面的递归是如何工作的,您就可以尝试将其做得更好一点。现在,为了找到实际的结果,我们也依赖于前面函数的值。在递归调用返回结果之前,
return
语句不能立即返回值。我们可以通过将电流传递给函数参数来避免这种情况,如下所示

>>> def listSum(ls, result):
...     if not ls:
...         return result
...     return listSum(ls[1:], result + ls[0])
... 
>>> listSum([1, 3, 4, 5, 6], 0)
19
>>> def listSum(ls):
...
...     def recursion(index, result):
...         if index == len(ls):
...             return result
...         return recursion(index + 1, result + ls[index])
...
...     return recursion(0, 0)
... 
>>> listSum([1, 3, 4, 5, 6])
19
>>> def listSum(ls, index=0, result=0):
...     # Base condition
...     if index == len(ls):
...         return result
...
...     # Call with next index and add the current element to result
...     return listSum(ls, index + 1, result + ls[index])
... 
>>> listSum([1, 3, 4, 5, 6])
19
power(2, 5, 1) = power(2, 4, 1 * 2)
               = power(2, 4, 2)
               = power(2, 3, 2 * 2)
               = power(2, 3, 4)
               = power(2, 2, 4 * 2)
               = power(2, 2, 8)
               = power(2, 1, 8 * 2)
               = power(2, 1, 16)
               = power(2, 0, 16 * 2)
               = power(2, 0, 32)
这里,我们在参数中传递和的初始值,在
listSum([1,3,4,5,6],0)
中为零。然后,当基本条件满足时,我们实际上是在
result
参数中累加总和,因此我们返回它。现在,最后一个
return
语句具有
listSum(ls[1:],result+ls[0])
,我们将第一个元素添加到当前
result
中,并将其再次传递给递归调用

这可能是一个理解的好时机。它与Python无关,因为它不进行尾部调用优化


传递索引版本

>>> def listSum(ls):
...     # Base condition
...     if not ls:
...         return 0
...
...     # First element + result of calling `listsum` with rest of the elements
...     return ls[0] + listSum(ls[1:])
>>> 
>>> listSum([1, 3, 4, 5, 6])
19
现在,您可能认为我们正在创建这么多中间列表。我可以避免吗

当然可以。您只需要下一步处理项目的索引。但现在,基本条件将有所不同。既然我们要传递索引,我们将如何确定整个列表是如何处理的?如果索引等于列表的长度,那么我们已经处理了列表中的所有元素

>>> def listSum(ls, index, result):
...     # Base condition
...     if index == len(ls):
...         return result
...
...     # Call with next index and add the current element to result
...     return listSum(ls, index + 1, result + ls[index])
... 
>>> listSum([1, 3, 4, 5, 6], 0, 0)
19

内部功能版本

>>> def listSum(ls):
...     # Base condition
...     if not ls:
...         return 0
...
...     # First element + result of calling `listsum` with rest of the elements
...     return ls[0] + listSum(ls[1:])
>>> 
>>> listSum([1, 3, 4, 5, 6])
19
如果现在查看函数定义,将向其传递三个参数。假设您要将此函数作为API发布。当用户实际找到列表的总和时,传递三个值是否方便

没有。我们能做些什么?我们可以创建另一个函数,它是实际的
listSum
函数的本地函数,我们可以将所有与实现相关的参数传递给它,如下所示

>>> def listSum(ls, result):
...     if not ls:
...         return result
...     return listSum(ls[1:], result + ls[0])
... 
>>> listSum([1, 3, 4, 5, 6], 0)
19
>>> def listSum(ls):
...
...     def recursion(index, result):
...         if index == len(ls):
...             return result
...         return recursion(index + 1, result + ls[index])
...
...     return recursion(0, 0)
... 
>>> listSum([1, 3, 4, 5, 6])
19
>>> def listSum(ls, index=0, result=0):
...     # Base condition
...     if index == len(ls):
...         return result
...
...     # Call with next index and add the current element to result
...     return listSum(ls, index + 1, result + ls[index])
... 
>>> listSum([1, 3, 4, 5, 6])
19
power(2, 5, 1) = power(2, 4, 1 * 2)
               = power(2, 4, 2)
               = power(2, 3, 2 * 2)
               = power(2, 3, 4)
               = power(2, 2, 4 * 2)
               = power(2, 2, 8)
               = power(2, 1, 8 * 2)
               = power(2, 1, 16)
               = power(2, 0, 16 * 2)
               = power(2, 0, 32)
现在,当调用
listSum
时,它只返回
递归
内部函数的返回值,该函数接受
索引
结果
参数。现在我们只传递这些值,而不是
listSum
的用户。他们只需要通过要处理的列表

在这种情况下,如果您观察这些参数,我们不会将
ls
传递给
递归
,而是在其中使用它<由于闭包属性,可以在
递归中访问code>ls


默认参数版本

>>> def listSum(ls):
...     # Base condition
...     if not ls:
...         return 0
...
...     # First element + result of calling `listsum` with rest of the elements
...     return ls[0] + listSum(ls[1:])
>>> 
>>> listSum([1, 3, 4, 5, 6])
19
现在,如果您想保持简单,而不创建内部函数,可以使用默认参数,如下所示

>>> def listSum(ls, result):
...     if not ls:
...         return result
...     return listSum(ls[1:], result + ls[0])
... 
>>> listSum([1, 3, 4, 5, 6], 0)
19
>>> def listSum(ls):
...
...     def recursion(index, result):
...         if index == len(ls):
...             return result
...         return recursion(index + 1, result + ls[index])
...
...     return recursion(0, 0)
... 
>>> listSum([1, 3, 4, 5, 6])
19
>>> def listSum(ls, index=0, result=0):
...     # Base condition
...     if index == len(ls):
...         return result
...
...     # Call with next index and add the current element to result
...     return listSum(ls, index + 1, result + ls[index])
... 
>>> listSum([1, 3, 4, 5, 6])
19
power(2, 5, 1) = power(2, 4, 1 * 2)
               = power(2, 4, 2)
               = power(2, 3, 2 * 2)
               = power(2, 3, 4)
               = power(2, 2, 4 * 2)
               = power(2, 2, 8)
               = power(2, 1, 8 * 2)
               = power(2, 1, 16)
               = power(2, 0, 16 * 2)
               = power(2, 0, 32)
现在,如果调用方没有显式传递任何值,则
0
将同时分配给
index
result


递归幂问题

现在,让我们把这些想法应用到另一个问题上。例如,让我们尝试实现
power(base,exponent)
函数。它会将
base
的值返回到幂
指数

power(2, 5) = 32
power(5, 2) = 25
power(3, 4) = 81
现在,我们怎样才能递归地做到这一点?让我们努力了解这些成果是如何取得的

power(2, 5) = 2 * 2 * 2 * 2 * 2 = 32
power(5, 2) = 5 * 5             = 25
power(3, 4) = 3 * 3 * 3 * 3     = 81
嗯,我们明白了。
乘以自身,
指数
得到结果。好吧,我们该怎么做。让我们尝试使用相同的函数定义解决方案

power(2, 5) = 2 * power(2, 4)
            = 2 * (2 * power(2, 3))
            = 2 * (2 * (2 * power(2, 2)))
            = 2 * (2 * (2 * (2 * power(2, 1))))
如果任何东西被提升到幂1,结果会是什么?结果将是相同的数字,对吗?我们得到了递归的基本条件:-)

好的,让我们实现它

>>> def power(base, exponent):
...     # Base condition, if `exponent` is lesser than or equal to 1, return `base`
...     if exponent <= 1:
...         return base
...
...     return base * power(base, exponent - 1)
... 
>>> power(2, 5)
32
>>> power(5, 2)
25
>>> power(3, 4)
81
由于
指数
变为零,基本条件得到满足,将返回
结果
,因此我们得到
32
:-)

另一个版本:

def listSum(ls):
    ls_len = len(ls)

    # Base condition
    if ls_len==1:
        return ls[0]
    if ls_len==0:
        return None
    # ls = listSum(ls[0:i]) + listSum(ls[i:])
    elif ls_len%2==0:
            i = int(ls_len/2)
            return listSum(ls[0:i]) + listSum(ls[i:])
    else:
        i = int((ls_len-1)/2)
        return listSum(ls[0:i]) + listSum(ls[i:])
按照@thefourtheye的例子,我们可以说:

listSum([1, 3, 4, 5, 6]) = listSum([1, 3]) + listSum([4, 5, 6])
                         = (listSum([1]) + listSum([3])) + (listSum([4]) + listSum([5, 6]))
                         = (listSum([1]) + listSum([3])) + (listSum([4]) + (listSum([5]) + listSum([6])))
基本条件:当
ls
只有一个元素时,返回此值

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

print(listsum([1,5,9,10,20]))
这个递归函数背后的基本思想是,我们要检查是否有一个基本情况,它显示为
if len(list)==1:
。对于基本情况,我们只返回列表中的值
返回列表[0]
,否则,列表中仍有多个元素。在
else:
语句中,我们将把列表中的第一个元素
list[0]
添加到列表中的其余元素中。这是通过递归调用函数来显示的,其中列表短1个元素——索引0处的元素--
listsum(list[1:])
,该过程随着列表变小而重复