我正在阅读Explore - LeetCode。
它用一个简单但很技巧的例子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)
但是,该过程是隐式的,似乎没有采取这样的步骤将所有字符堆叠在一起,而是立即跳转到for c in stack, print(c)
如何设计调试程序以查看生成调用堆栈的过程?
答案 0 :(得分:1)
您致电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')
框架在打印helper(1, 'string')
的{{1}}之前等待'string'[0]'
的结果。s
框架等待helper(1, 'string')
的结果,然后打印helper(2, 'string')
的{{1}} 'string'[1]'
等待t
的结果helper(5, 'string')
与helper(6, 'string')
有所不同。 helper(6, 'string')
被触发,并且结果为6 >= len('string')
-它不必等待任何东西!if
的结果为None
,并进行到helper(5, 'string')
语句。最后一个字符helper(6, 'string')
出现在屏幕上。print
的结果为g
,可以继续执行print语句,您将获得helper(4, 'string')
。helper(5, 'string')
的结果,并且原始呼叫n
可以打印helper(1, 'string')
。您可以使用pdb模块暂停Python程序并逐行执行。