Python 使用递归printReverse字符串的机制

Python 使用递归printReverse字符串的机制,python,algorithm,Python,Algorithm,我正在读书 它用一个简单但巧妙的例子printReverse 让我们从一个简单的编程问题开始: 按相反顺序打印字符串 您可以轻松地迭代解决此问题,即从字符串的最后一个字符开始循环字符串。但是递归地解决它怎么样 首先,我们可以将所需函数定义为printReverse(str[0…n-1]),其中str[0]表示字符串中的第一个字符。然后我们可以分两步完成给定的任务: printReverse(str[1…n-1]):按相反顺序打印子字符串str[1…n-1] print(str[0]):打印字符串

我正在读书

它用一个简单但巧妙的例子
printReverse

让我们从一个简单的编程问题开始:

按相反顺序打印字符串

您可以轻松地迭代解决此问题,即从字符串的最后一个字符开始循环字符串。但是递归地解决它怎么样

首先,我们可以将所需函数定义为
printReverse(str[0…n-1])
,其中
str[0]
表示字符串中的第一个字符。然后我们可以分两步完成给定的任务:

  • printReverse(str[1…n-1])
    :按相反顺序打印子字符串
    str[1…n-1]
  • print(str[0])
    :打印字符串中的第一个字符
  • 请注意,我们在第一步中调用函数本身,根据定义,这会使函数递归

    实施

    import unittest
    import logging 
    logging.basicConfig(level=logging.DEBUG, format="%(levelname)s %(message)s")
    
    def printReverse(s):
        helper(0, s)
    
    def helper(idx, s):
        if s == None or idx >= len(s):
            return 
        logging.debug(f"index:{idx}")
        helper(idx+1, s)
        print(s[idx])
    
    class MyCase(unittest.TestCase):
    
        def test_printReverse(self):
            s = 'string'
            printReverse(s)
    
    unittest.main()
    
    我对它的工作原理感到非常困惑。特别是第一个s[0]不是s而是g

    $ python printReverse.py 
    DEBUG index:0
    DEBUG index:1
    DEBUG index:2
    DEBUG index:3
    DEBUG index:4
    DEBUG index:5
    g
    n
    i
    r
    t
    s
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    OK
    
    我已确认调用堆栈正在作为

    def printReverse2(s):
        stack = []
        for c in s:
            stack.append(c)
        for c in stack:
            print(c)
    
    然而,这个过程是隐式的,似乎没有这样的步骤将所有字符放入堆栈,而是立即跳转到
    对于堆栈中的c,打印(c)

    如何设计调试以查看生成调用堆栈的过程?
    .

    您调用
    printReverse('string')
    它调用
    helper(0,'string')
    。这很清楚

    但是我们如何得到结果呢?
    print(s[idx])
    行应该打印
    s
    ——第一个字符,对吗?但是等等,Python解释器必须首先执行前一行,即
    helper(idx+1,s)

    执行该语句意味着Python必须弹出该执行的结果值(在您的例子中,helper不返回任何值,即None),事实上,对于
    t,r,i,n,g
    中的每一个,都有一个新的堆栈帧。看起来怎么样

  • 使用
    helper(0,'string')
  • helper(0,'string')
    frame等待
    helper(1,'string')
    的结果,然后打印
    'string'[0]'
    ,即
    s
  • helper(1,'string')
    frame等待
    helper(2,'string')
    的结果,然后打印
    'string'[1]'
    ,即
    t
  • helper(5,'string')
    等待
    helper(6,'string')
  • helper(6,'string')
    有点不同,因为
    6>=len('string')
    。如果触发了
    ,并且它有一个结果
    None
    -它不需要等待任何东西
  • 现在
    helper(5,'string')
    得到了
    helper(6,'string')
    的结果,并继续执行
    print
    语句。最后一个字符
    g
    出现在屏幕上
  • helper(4,'string')
    具有
    helper(5,'string')
    的结果,可以继续执行print语句,得到一个
    n
  • 。。。等等
  • …直到得到
    helper(1,'string')
    的结果以及原始调用
    helper(0,'string')
    才能打印
    s

  • 您可以使用该模块暂停Python程序并逐行执行它。

    对于堆栈中的c来说,这不是
    ,更像是
    而c=stack.pop()
    。项目以后进先出的顺序从堆栈中弹出。换句话说,相反。将所有字符放入堆栈的代码部分是递归调用(
    helper(idx+1,s)
    )。是的,当c=stack.pop()是智能的,并且是PEP 572样式的@BlorgbeardNow,我很清楚他一直在理解尾部递归的堆栈过程
    helper(idx+1,s)
    @BlorgbeardSorry,我不明白这个问题-你能说得更清楚吗?感谢你的详细解释,Brilliant。你无法想象我现在有多高兴。英雄联盟