![](/img/trans.png)
[英]How can i replace a recursive function in python with a non recursive code?
[英]How can I count the recursive calls of a function in Python?
我在玩递归Ackermanns函数。 对于某些值,我的提示谁不能显示每个计算出的输出,这是因为Python会如此快地超过其递归限制,以致于谁会冻结提示,而不是赶上它的“简单”部分。
因此,我认为我可以在函数完全执行后添加递归计数器和快速暂停。 我得到了预期的输出,直到达到值(1,0)。 之后,我得到一个TypeError: can only concatenate tuple (not "int") to tuple
。
我的代码如下:
import time
import sys
sys.setrecursionlimit(3000)
def ackermann(i,j,rec):
output = None
if i==0:
output = j+1
elif j==0:
output = ackermann(i-1,1,rec)
rec=rec+1
else:
output = ackermann(i-1,ackermann(i,j-1,rec),rec)
rec=rec+1
return output,rec
rec=0
for i in range(5):
for j in range(5):
print("(",i,",",j,")= ",ackermann(i,j,rec))
time.sleep(2)
请注意,删除rec
(我的递归计数器)的所有实例后,程序运行正常。 (您可以看到值i,j = 3
所有输出)
有人可以指出如何更正我的代码或提出另一种方法来查找Ackermann函数调用自身的次数吗?
另外,我注意到将限制设置为5000会使我的python内核很快崩溃。 有上限吗?
我使用最新的Anaconda。
编辑
我尝试使用列表作为参数并使用以下数据[i,j,output,#recursion]
实现相同的功能
import time
import sys
sys.setrecursionlimit(3000)
def ackermann(*rec):
rec=list(rec)
print(rec) # see the data as they initialize the function
if rec[0][0]==0:
rec[0][1]=rec[0][1]+1
rec[0][2] = rec[0][1]+1
elif rec[0][1]==0:
rec[0][0]=rec[0][0]-1
rec[0][1]=1
rec = ackermann()
rec[0][3]=rec[0][3]+1
else:
rec[0][0]=rec[0][0]-1
rec[0][1] = ackermann()
rec = ackermann()
rec[0][3]=rec[0][3]+1
return rec
for i in range(5):
for j in range(5):
rec=[i,j,0,0]
print(ackermann(rec))
time.sleep(1)
但是这次我得到一个IndexError: list index out of range
因为出于某些未知原因,我的列表被清空了
OUTPUT:
[[0, 0, 0, 0]]
[[0, 1, 2, 0]]
[[0, 1, 0, 0]]
[[0, 2, 3, 0]]
[[0, 2, 0, 0]]
[[0, 3, 4, 0]]
[[0, 3, 0, 0]]
[[0, 4, 5, 0]]
[[0, 4, 0, 0]]
[[0, 5, 6, 0]]
[[1, 0, 0, 0]]
[]
原始实现的问题是,当output和rec均为数字时, return output,rec会很高兴地创建一个元组,只要i = 0,这都是正确的。 但是一旦达到i = 1,j = 0,函数就会在(0,1,rec)上调用Ackerman,这将返回一个元组,然后它不能向其添加整数rec,因此会出现错误消息。 我相信我已经采用了这个想法,但是几乎没有改变,只是我没有尝试传递和返回rec,而是使它成为全局的(丑陋,我知道)。 我还重新格式化了输出,以便可以更好地阅读。 从而:
import time
import sys
sys.setrecursionlimit(3000)
def ackermann(i,j):
global rec
output = None
if i==0:
output = j+1
elif j==0:
output = ackermann(i-1,1)
rec=rec+1
else:
output = ackermann(i-1,ackermann(i,j-1))
rec=rec+1
return output
for i in range(5):
for j in range(5):
rec = 0
print
print("ack("+str(i)+","+str(j)+") = "+str(ackermann(i,j)))
print("rec = "+str(rec))
print
time.sleep(1)
在错误输出之前的输出是
ack(0,0) = 1
rec = 0
ack(0,1) = 2
rec = 0
ack(0,2) = 3
rec = 0
ack(0,3) = 4
rec = 0
ack(0,4) = 5
rec = 0
ack(1,0) = 2
rec = 1
ack(1,1) = 3
rec = 2
ack(1,2) = 4
rec = 3
ack(1,3) = 5
rec = 4
ack(1,4) = 6
rec = 5
ack(2,0) = 3
rec = 3
ack(2,1) = 5
rec = 8
ack(2,2) = 7
rec = 15
ack(2,3) = 9
rec = 24
ack(2,4) = 11
rec = 35
ack(3,0) = 5
rec = 9
ack(3,1) = 13
rec = 58
ack(3,2) = 29
rec = 283
ack(3,3) = 61
rec = 1244
ack(3,4) = 125
rec = 5213
ack(4,0) = 13
rec = 59
在我看来,只有一个或两个其他值(无论如何,它将使4,2窒息,所以您需要先获得5、0),无论如何,您都希望以此方式摆脱困境你很想
我对rec似乎超出了递归限制感到有些困惑,但我认为Python必须以某种方式进行解释,这样它的作用会超出人们的想象,或者我无法完全理解sys.recursionlimit(我看着在录制几次后,至少我遵循了您的指导进行计算;此外,作为健全性检查,我切换了递增顺序和函数调用的顺序,并得到了相同的结果)。
编辑:我添加了另一个参数来跟踪任何特定调用的重复深度。 事实证明,它通常小于(最多至多)“ rec”。 rec表示(实际上比实际少1倍)调用该函数进行特定计算的次数,但并非所有这些都需要同时在Python解释器堆栈上进行。
修改后的代码:
import time
import sys
sys.setrecursionlimit(3000)
def ackermann(i,j,d):
global rec
global maxDepth
if ( d > maxDepth ) : maxDepth = d
output = None
if i==0:
output = j+1
elif j==0:
rec=rec+1
output = ackermann(i-1,1, d+1)
else:
rec=rec+1
output = ackermann(i-1,ackermann(i,j-1, d+1),d+1)
return output
for i in range(5):
for j in range(5):
rec = 0
maxDepth=0
print
print("ack("+str(i)+","+str(j)+") = "+str(ackermann(i,j,1)))
print("rec = "+str(rec))
print("maxDepth = "+str(maxDepth))
print
time.sleep(1)
修改后的输出(在放弃之前)
ack(0,0) = 1
rec = 0
maxDepth = 1
ack(0,1) = 2
rec = 0
maxDepth = 1
ack(0,2) = 3
rec = 0
maxDepth = 1
ack(0,3) = 4
rec = 0
maxDepth = 1
ack(0,4) = 5
rec = 0
maxDepth = 1
ack(1,0) = 2
rec = 1
maxDepth = 2
ack(1,1) = 3
rec = 2
maxDepth = 3
ack(1,2) = 4
rec = 3
maxDepth = 4
ack(1,3) = 5
rec = 4
maxDepth = 5
ack(1,4) = 6
rec = 5
maxDepth = 6
ack(2,0) = 3
rec = 3
maxDepth = 4
ack(2,1) = 5
rec = 8
maxDepth = 6
ack(2,2) = 7
rec = 15
maxDepth = 8
ack(2,3) = 9
rec = 24
maxDepth = 10
ack(2,4) = 11
rec = 35
maxDepth = 12
ack(3,0) = 5
rec = 9
maxDepth = 7
ack(3,1) = 13
rec = 58
maxDepth = 15
ack(3,2) = 29
rec = 283
maxDepth = 31
ack(3,3) = 61
rec = 1244
maxDepth = 63
ack(3,4) = 125
rec = 5213
maxDepth = 127
ack(4,0) = 13
rec = 59
maxDepth = 16
在代码的编辑版本中,您在ackerman的def中使用了* arg并将其明确地指定为一个列表,然后获得了11个输出列表,每个列表中都包含一个四元素列表,直到第十二次递归时您得到一个空列表。 那么,根据ackermann约束,前11个列表是否包含预期元素? 另外,在第十二次递归中,您说列表被“清空了”。 我想从分析的角度出发说它不是一开始就有意义吗? 就是说,不是倒空了某些东西,而是没有像第十二次那样充满它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.