如何计算值在递归函数中重现的次数?

时间:2017-01-07 00:58:31

标签: python recursion combinatorics

如果你有一个递归函数(例如Fibonacci序列):

def fib(n):
    """Return Fibonacci of n; assumes n is an int >= 0."""
    if n == 0 or n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

如何计算,例如,当调用fib(20)时,fib(2)发生的次数?

10 个答案:

答案 0 :(得分:2)

你可以使用装饰者:

import functools

def count(f):
    """Count function calls."""
    @functools.wraps(f)
    def counted(*args, **kwargs):
        counted.count_calls += 1
        return f(*args, **kwargs)
    counted.count_calls = 0
    return counted

fib = count(fib)
fib(5)
fib.count_calls
# 15

或者,您现在可以使用此装饰器和@符号添加任何函数定义:

@count
def fib(n):
    ...

fib(5)
fib.count_calls
# 15

注意,这个装饰器会累积函数调用:

fib(5)
fib(5)
fib.count_calls
# 30

这是一个利用鲜为人知的function attributes的聪明实现。请注意,原始装饰器是根据他在lecture on Memoization中讨论的John DiNero的count函数进行修改的,在那里他解决了这个特定问题。

答案 1 :(得分:1)

您可以使用字典来计算fib的所有调用。在第一次调用fib之前必须清除字典。

calls = defaultdict(int)

在函数中,在执行任何其他操作之前更新字典中的相应条目:

def fib(n):
  global calls
  """Assumes n an int >= 0
     Returns Fibonacci of n"""
  calls[n] += 1
  if n == 0 or n == 1:
    return 1
  else:
    return fib(n-1) + fib(n-2)

答案 2 :(得分:1)

怎么样:

def fib(n, counts_dict):
    counts_dict[n] += 1
    if n == 0 or n == 1:
        return 1
    else:
        return fib(n-1, counts_dict) + fib(n-2, counts_dict

counts_dict = collections.defaultdict(int)

答案 3 :(得分:1)

这就是我的尝试...认为工作正常

def fib(n):
    global counter
    if (n == 0 or n == 1):
        counter=counter+1
        return 1
    else:
        counter=counter+1
        return fib(n-1) + fib(n-2)
def countfib(n):
    global counter
    counter = 0
    fib(5);
    global count
    count=counter
    counter = 0
    return count
counter=0
count=0
print fib(5)
count=countfib(5)
print count

输出:

  

8
  15

答案 4 :(得分:1)

我不清楚你想要计算的重复值是什么,所以我猜它是用同一个参数调用(递归)函数的次数(或者它们的组,如果超过一个)。

在下面的代码中,名为tally_recurring_args()的装饰器用于将函数包装在某些代码中以执行此操作。为了简化操作并避免重新发明轮子,collections.Counter用于计算函数的每个唯一参数组合的调用次数。这是函数的一个属性,因此可以在wrapper每次调用装饰函数时轻松引用它。

import collections
import functools

def tally_recurring_args(func):
    func._args_counter = collections.Counter()  @ add attribute to func

    @functools.wraps(func)
    def wrapper(*args):
        key = ', '.join(str(arg) for arg in args)
        func._args_counter[key] += 1
        return func(*args)

    return wrapper

@tally_recurring_args
def fib(n):
    """Return Fibonacci of n; assumes n is an int >= 0."""
    if n == 0 or n == 1:
        return 1
    else:
        return fib(n-1) + fib(n-2)

print('fib(5) -> {}'.format(fib(5)))
for args, count in sorted(fib._args_counter.items()):
    print('fib({}): called {} time{}'.format(args, count,
                                             's' if count > 1 else ''))

输出:

fib(5) -> 8
fib(0): called 3 times
fib(1): called 5 times
fib(2): called 3 times
fib(3): called 2 times
fib(4): called 1 time
fib(5): called 1 time

答案 5 :(得分:0)

def fib(n, x):
    c = 1 if n == x else 0

    if n == 0 or n == 1:
        return 1, c
    else:
        fA, cA = fib(n - 1, x)
        fB, cB = fib(n - 2, x)
        return fA + fB, cA + cB + c

如果我没有弄乱逻辑,则此函数接受nx并返回元组(y, c) s.t.在计算过程中fib(n, _)=yfib(x, _)被调用了c次。

这是涉及更新字典的其他提议解决方案的更纯粹的替代方案。它基于这样的假设,即OP仅需要为一个特定f(k, _)调用k的次数,因此避免填写只需要一个值的字典。

答案 6 :(得分:0)

没有全局变量:

from collections import defaultdict
def fib(n, count=None):
    if count is None:
        count = defaultdict(int)
    count[n] += 1
    if n in (0, 1):
        return 1, count
    return fib(n - 1)[0] + fib(n - 2)[0], count

fib函数现在返回一个元组:第一个元素是所需的值,第二个元素是一个字典,其中包含调用fib函数的每个值的次数的信息。 / p>

答案 7 :(得分:0)

如何使用函数属性。就像一个静态变量。

def fib(n): 
    """Return Fibonacci of n; assumes n is an int >= 0."""
    If hasattr(fib, 'cnt'):
        fib.cnt += 1
    else:
        fib.cnt = 1
    if n == 0 or n == 1: 
        return 1 
    else: 
        return fib(n-1) + fib(n-2)

fib.cnt =0

答案 8 :(得分:0)

使用全局:

c = 0
def fib(n):
    global c
    c += 1
    if n == 1:
        return 0
    elif n == 2:
        return 1
    else:
        return fib(n-1) + fib(n-2)

答案 9 :(得分:0)

这是另一个没有全局变量的解决方案,但是通过传递值来完成:

def fibo(n, c):
if n <= 2 and n > 0:
    return n-1, c
else:
    n1, c1 = fibo(n-1,c+1)
    n2, c2 = fibo(n-2,1)
    return n1+n2, c1+c2