Python : 递归调用的执行计数
Python : Counting execution of recursive call
我在学习 Python 3.x 时使用欧拉问题来测试我的理解。在我为每个问题拼凑出一个可行的解决方案后,我发现发布的解决方案非常有启发性,并且在我自己努力之后我可以 "absorb" 新的想法。我正在研究 Euler 024,我正在尝试一种递归方法。现在,我绝不相信我的方法是最有效或最优雅的,但是,我成功地生成了一整套排列,增加了价值(因为我从一个排序的元组开始)——这是我想要的输出之一.此外,为了找到列表中的百万分之一(这是我想要的另一个输出,但还不能得到),我试图计算每次创建排列时有多少,这就是我卡住的地方。换句话说,我想做的是每次到达基本情况时计算递归调用的次数,即完成的排列,而不是递归调用的总数。我在 Whosebug 上找到了一些非常清楚的计算递归调用执行次数的示例,但我没有运气将这个想法应用到我的代码中。到目前为止,我在尝试中遇到的问题基本上是关于 "passing back" 使用 return 语句的 "completed" 排列的计数。我认为我需要这样做,因为我的 for 循环创建 "stem" 和 "tail" 元组的方式。在高层次上,要么我无法让计数器递增(因此它总是以“1”或“5”出现),要么 "nested return" 只是在找到第一个排列后终止代码,具体取决于我把 return 放在哪里。任何人都可以帮助将计数插入我的代码吗?
首先是我在 SO 中找到的我正在尝试使用的 "counting" 代码:
def recur(n, count=0):
if n == 0:
return "Finished count %s" % count
return recur(n-1, count+1)
print(recur(15))
接下来是我的排列代码,其中没有计数。我尝试了很多方法,但其中 none 有效。所以下面没有 "counting" ,只是在代码中我认为计数器需要递增的地方的注释。
#
# euler 024 : Lexicographic permutations
#
import time
startTime= time.time()
#
def splitList(listStem,listTail):
for idx in range(0,len(listTail)):
tempStem =((listStem) + (listTail[idx],))
tempTail = ((listTail[:idx]) + (listTail[1+idx:]))
splitList(tempStem,tempTail)
if len(listTail) ==0:
#
# I want to increment counter only when I am here
#
print("listStem=",listStem,"listTail=",listTail)
#
inStem = ()
#inTail = ("0","1","2","3","4","5","6","7","8","9")
inTail = ("0","1","2","3")
testStem = ("0","1")
testTail = ("2","3","4","5")
splitList(inStem,inTail)
#
print('Code execution duration : ',time.time() - startTime,' seconds')
提前致谢,
克莱夫
你为什么不为此编写生成器?
然后你可以停在第 n
项 ("drop while i < n")。
我的解决方案使用的是 itertools
,但您可以使用自己的排列生成器。只是 yield
下一个序列成员而不是打印它。
from itertools import permutations as perm, dropwhile as dw
print(''.join(dw(
lambda x: x[0]<1000000,
enumerate(perm('0123456789'),1)
).__next__()[1]))
由于您似乎已经理解了基本问题,但只是想了解递归是如何发生的,所以您需要做的就是传递一个变量,告诉您您在调用堆栈的哪个位置。您可以向函数添加第三个参数,并在每次递归调用时递增它:
def splitList(listStem, listTail, count):
for idx in range(0,len(listTail)):
...
splitList(tempStem, tempTail, count)
if len(listTail) == 0:
count[0] += 1
print('Count:', count)
...
现在,像这样调用这个函数(和以前一样):
splitList(inStem, inTail, [0])
我在学习 Python 3.x 时使用欧拉问题来测试我的理解。在我为每个问题拼凑出一个可行的解决方案后,我发现发布的解决方案非常有启发性,并且在我自己努力之后我可以 "absorb" 新的想法。我正在研究 Euler 024,我正在尝试一种递归方法。现在,我绝不相信我的方法是最有效或最优雅的,但是,我成功地生成了一整套排列,增加了价值(因为我从一个排序的元组开始)——这是我想要的输出之一.此外,为了找到列表中的百万分之一(这是我想要的另一个输出,但还不能得到),我试图计算每次创建排列时有多少,这就是我卡住的地方。换句话说,我想做的是每次到达基本情况时计算递归调用的次数,即完成的排列,而不是递归调用的总数。我在 Whosebug 上找到了一些非常清楚的计算递归调用执行次数的示例,但我没有运气将这个想法应用到我的代码中。到目前为止,我在尝试中遇到的问题基本上是关于 "passing back" 使用 return 语句的 "completed" 排列的计数。我认为我需要这样做,因为我的 for 循环创建 "stem" 和 "tail" 元组的方式。在高层次上,要么我无法让计数器递增(因此它总是以“1”或“5”出现),要么 "nested return" 只是在找到第一个排列后终止代码,具体取决于我把 return 放在哪里。任何人都可以帮助将计数插入我的代码吗?
首先是我在 SO 中找到的我正在尝试使用的 "counting" 代码:
def recur(n, count=0):
if n == 0:
return "Finished count %s" % count
return recur(n-1, count+1)
print(recur(15))
接下来是我的排列代码,其中没有计数。我尝试了很多方法,但其中 none 有效。所以下面没有 "counting" ,只是在代码中我认为计数器需要递增的地方的注释。
#
# euler 024 : Lexicographic permutations
#
import time
startTime= time.time()
#
def splitList(listStem,listTail):
for idx in range(0,len(listTail)):
tempStem =((listStem) + (listTail[idx],))
tempTail = ((listTail[:idx]) + (listTail[1+idx:]))
splitList(tempStem,tempTail)
if len(listTail) ==0:
#
# I want to increment counter only when I am here
#
print("listStem=",listStem,"listTail=",listTail)
#
inStem = ()
#inTail = ("0","1","2","3","4","5","6","7","8","9")
inTail = ("0","1","2","3")
testStem = ("0","1")
testTail = ("2","3","4","5")
splitList(inStem,inTail)
#
print('Code execution duration : ',time.time() - startTime,' seconds')
提前致谢,
克莱夫
你为什么不为此编写生成器?
然后你可以停在第 n
项 ("drop while i < n")。
我的解决方案使用的是 itertools
,但您可以使用自己的排列生成器。只是 yield
下一个序列成员而不是打印它。
from itertools import permutations as perm, dropwhile as dw
print(''.join(dw(
lambda x: x[0]<1000000,
enumerate(perm('0123456789'),1)
).__next__()[1]))
由于您似乎已经理解了基本问题,但只是想了解递归是如何发生的,所以您需要做的就是传递一个变量,告诉您您在调用堆栈的哪个位置。您可以向函数添加第三个参数,并在每次递归调用时递增它:
def splitList(listStem, listTail, count):
for idx in range(0,len(listTail)):
...
splitList(tempStem, tempTail, count)
if len(listTail) == 0:
count[0] += 1
print('Count:', count)
...
现在,像这样调用这个函数(和以前一样):
splitList(inStem, inTail, [0])