理解递归函数

时间:2013-08-03 02:13:16

标签: python-2.7 recursion

我正在阅读使用Python的NLP一书,我从“高级”部分看到了这个例子。我很感激帮助理解它是如何工作的。该函数计算多个音节的所有可能性,以达到'米'长度n。短音节“S”占据一个单位的长度,而长音节“L”占据两个单位的长度。因此,对于4米的长度,return语句如下所示:

['SSSS', 'SSL', 'SLS', 'LSS', 'LL']

功能:

def virahanka1(n):
    if n == 0:
        return [""]
    elif n == 1:
        return ["S"]
    else:
        s = ["S" + prosody for prosody in virahanka1(n-1)]
        l = ["L" + prosody for prosody in virahanka1(n-2)]
        return s + l

我不明白的部分是如果s和l是单独的列表,如何匹配'SSL','SLS'和'LSS'。同样在“virahanka1(n-1)中的韵律”中,什么是韵律?这是函数每次返回的内容吗?我正试图一步一步地思考它,但我没有到达任何地方。在此先感谢您的帮助!

阿德里安

3 个答案:

答案 0 :(得分:2)

让我们从头开始构建函数。这是彻底理解它的好方法。

假设我们想要一个递归函数来枚举Ls和Ss的每个组合,以产生给定的米长n。我们只考虑一些简单的案例:

  • n = 0:只有这样才能使用空字符串。
  • n = 1:只有这样才能使用单个S。
  • n = 2:您可以使用单个L或两个S来执行此操作。
  • n = 3:LS,SL,SSS。

现在,考虑一下上述数据,你可以考虑如何为n = 4建立答案。那么,答案要么是将S添加到3米的长度,要么将L增加到2米的长度。因此,在这种情况下,答案是LL, LSS,从n = 2和{{1来自SLS, SSL, SSSS。您可以检查这是否是所有可能的组合。我们还可以看到n = 3n = 2可以从n = 0,1和n = 1,2获得,因此我们不需要特殊情况。

通常,对于n = 3,您可以通过查看长度为n ≥ 2和长度为n的字符串来推导长度为n-1的字符串。

然后,答案很明显:

  • 如果n = 0,则只返回一个空字符串
  • 如果n = 1,则返回单个S
  • 否则,将结果添加到所有米长度n-2的字符串中,并将结果与​​向仪表长度n-1的所有字符串添加L的结果相结合。

顺便说一句,写入的函数效率有点低,因为它会重新计算很多值。如果你要求例如,那将会非常缓慢n-2。通过使用Python 3.3中的新n = 30

,您可以非常轻松地加快速度
lru_cache

此缓存每个@lru_cache(maxsize=None) def virahanka1(n): ... 的结果,使其更快。

答案 1 :(得分:1)

我试图融化我的大脑。我添加了印刷语句来向我解释发生了什么。我认为关于递归调用最令人困惑的部分是它似乎进入了调用转发但是向后退出,正如您在运行以下代码时可能会看到的那样;

def virahanka1(n):
    if n == 4:
            print 'Lets Begin for ', n
    else:
            print 'recursive call for ', n, '\n'
    if n == 0:
        print 'n = 0 so adding "" to below'
        return [""]
    elif n == 1:
        print 'n = 1 so returning S for below'
        return ["S"]
    else:
        print 'next recursivly call ' + str(n) + '-1 for S'
        s = ["S" + prosody for prosody in virahanka1(n-1)]
        print '"S" + each string in s equals', s
        if n == 4:
            print '**Above is the result for s**'
        print 'n =',n,'\n', 'next recursivly call ' + str(n) + '-2 for L'
        l = ["L" + prosody for prosody in virahanka1(n-2)]
        print '\t','what was returned + each string in l now equals', l
        if n == 4:
            print '**Above is the result for l**','\n','**Below is the end result of s + l**'
        print 'returning s + l',s+l,'for below', '\n','='*70
        return s + l
virahanka1(4)

对我来说仍然感到困惑,但有了这个和Jocke的优雅解释,我想我能理解发生了什么。

你呢?

以下是上面的代码产生的内容;

Lets Begin for  4
next recursivly call 4-1 for S
recursive call for  3

next recursivly call 3-1 for S
recursive call for  2

next recursivly call 2-1 for S
recursive call for  1

n = 1 so returning S for below
"S" + each string in s equals ['SS']
n = 2
next recursivly call 2-2 for L
recursive call for  0

n = 0 so adding "" to below
        what was returned + each string in l now equals ['L']
returning s + l ['SS', 'L'] for below
======================================================================
"S" + each string in s equals ['SSS', 'SL']
n = 3
next recursivly call 3-2 for L
recursive call for  1

n = 1 so returning S for below
        what was returned + each string in l now equals ['LS']
returning s + l ['SSS', 'SL', 'LS'] for below
======================================================================
"S" + each string in s equals ['SSSS', 'SSL', 'SLS']
**Above is the result for s**
n = 4
next recursivly call 4-2 for L
recursive call for  2

next recursivly call 2-1 for S
recursive call for  1

n = 1 so returning S for below
"S" + each string in s equals ['SS']
n = 2
next recursivly call 2-2 for L
recursive call for  0

n = 0 so adding "" to below
        what was returned + each string in l now equals ['L']
returning s + l ['SS', 'L'] for below
======================================================================
        what was returned + each string in l now equals ['LSS', 'LL']
**Above is the result for l**
**Below is the end result of s + l**
returning s + l ['SSSS', 'SSL', 'SLS', 'LSS', 'LL'] for below
======================================================================

答案 2 :(得分:0)

这个功能说:

virakhanka1(n)为零时,

[""]n相同,["S"]为1时为n,否则为s + l。 其中s"S"结果列表中每个元素的virahanka1(n - 1)前缀相同,l"L"前面的virahanka1(n - 2)相同When n is 0: [""] When n is 1: ["S"] When n is 2: s = ["S" + "S"] l = ["L" + ""] s + l = ["SS", "L"] When n is 3: s = ["S" + "SS", "S" + "L"] l = ["L" + "S"] s + l = ["SSS", "SL", "LS"] When n is 4: s = ["S" + "SSS", "S" + "SL", "S" + "LS"] l = ["L" + "SS", "L" + "L"] s + l = ['SSSS", "SSL", "SLS", "LSS", "LL"] 的元素。

所以计算将是:

prosody

然后你就一步一步地拥有它。

你需要知道其他函数调用的结果才能计算最终值,如你所见,这可能会非常麻烦。重要的是,你不要试图递归地思考。这会让你的思绪融化。我用单词描述了这个函数,这样你就可以看到这些函数是是描述,而不是一系列命令。

您看到的sl和{{1}}定义的一部分,是变量。它们用于列表理解,这是一种构建列表的方法。我之前已经描述过如何建立这个列表。