我有一个加泰罗尼亚数字的递归代码。 我设法写了递归调用,但由于某种原因,计数器无法正常工作。 例如,第7个加泰罗尼亚语号码的呼叫数量应为1215。 返回值需要是加泰罗尼亚语数和调用次数的元组,例如:(429,1215)。 原始代码:
def catalan_rec(n):
if n<=1:
return 1
res=0
for i in range(n):
res+=catalan_rec(i)*catalan_rec(n-i-1)
return res
计数器代码:
def catalan_rec_count(n,counter=1):
if n<=1:
return 1
res=0
for i in range(n):
res+=catalan_rec_count(i,counter+1)*catalan_rec_count(n-i-1,counter+1)
return (res,counter)
提前感谢!
答案 0 :(得分:7)
python允许您将变量(catalan.counter
附加到下面的代码段中)添加到函数对象中,因此您不必一直通过计数器并且不需要全局变量:
def catalan(n):
catalan.counter += 1
if n <= 1:
return 1
res = 0
for i in range(n):
res += catalan(i) * catalan(n-i-1)
return res
catalan.counter = 0
print(catalan(5))
print(catalan.counter)
并且看到使用相同的参数多次调用该函数:为了提高效率,您可以使用lru_cache
;但这当然违背了计算函数调用次数的目的;您只能使用唯一 n
获取调用该函数的编号。
from functools import lru_cache
@lru_cache(maxsize=128)
def catalan(n):
...
这可能有点偏离主题......但是如果您需要使用单独的计数器单独使用该函数的实例,closure可能就是您所需要的:
def make_catalan():
counter = 0
def catalan(n):
nonlocal counter
counter += 1
catalan.counter = counter
if n <= 1:
return 1
res = 0
for i in range(n):
res += catalan(i) * catalan(n-i-1)
return res
return catalan
catalan_1 = make_catalan()
print(catalan_1(2))
print(catalan_1.counter)
catalan_2 = make_catalan()
print(catalan_2(3))
print(catalan_2.counter)
答案 1 :(得分:5)
你需要分开行res+=catalan_rec_count(i,counter+1)*catalan_rec_count(n-i-1,counter+1)
,以便它可以单独对递归结果和计数器进行操作,所以只需将它分成几行,在这种情况下你也不会这样做。 t将counter+1
传递给递归调用,以便跟踪它与当前帧无关的调用。
def catalan_rec_count(n,counter=1):
if n<=1:
return (1, counter) #remember to return the counter in this case too!
res=0
for i in range(n):
#get the recursive results and counters for both calls
#don't pass counter+1 to it, it should count how many times it is called on it's own
partial1, inner_c1 = catalan_rec_count(i)
partial2, inner_c2 = catalan_rec_count(n-i-1)
#apply the logic with the actual result and add to the counter
res+=partial1*partial2
counter+= inner_c1 + inner_c2
return (res,counter)
答案 2 :(得分:0)
您可以设置一个类的实例,为要跟踪调用的函数提供计数器和装饰器方法。当装饰器函数被调用时,它会增加计数并将参数传递给被跟踪的函数。
这样,无需对函数的内部、参数或返回类型或使用全局变量进行任何调整——只需装饰和滚动即可。
import functools
class CallCounter:
def __init__(self):
self.call_count = 0
def count_calls(self, fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
self.call_count += 1
return fn(*args, **kwargs)
return wrapper
if __name__ == "__main__":
call_counter = CallCounter()
@call_counter.count_calls
def catalan_rec(n):
if n<=1:
return 1
res=0
for i in range(n):
res+=catalan_rec(i)*catalan_rec(n-i-1)
return res
# or without a decorator:
#call_counter = CallCounter()
#catalan_rec = call_counter.count_calls(catalan_rec)
print(catalan_rec(n=7)) # => 429
print(call_counter.call_count) # => 1215