python:如何计算我的递归函数执行的次数?

时间:2018-02-08 22:23:18

标签: python recursion

假设我有一个二叉搜索树[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]

如果我运行以下函数,我想知道递归函数执行了多少次(在下面的例子中,它是31)

def loopBST(root):
    if not root:
        return
    loopBST(root.left)
    loopBST(root.right)

我可以通过创建一个全局变量来获得这个

global ind 
ind = 0
def loopBST(root):
    global ind
    ind += 1
    if not root:
        return
    loopBST(root.left)
    loopBST(root.right)
loopBST(bsttree)

变量ind将为31。

问题是,如何在ind函数中创建dfs而不是创建全局变量?

4 个答案:

答案 0 :(得分:4)

您可以使用参数。

def loopBST(root, times=0):
    times += 1
    if not root:
        return times
    times = loopBST(root.left, times=times)
    times = loopBST(root.right, times=times)
    return times
loopBST(bsttree)

答案 1 :(得分:4)

您可以返回执行次数:

def loopBST(root):
    if not root:
        return 1
    return 1 + loopBST(root.left) + loopBST(root.right)

答案 2 :(得分:2)

如果你不想重写你的递归函数,你也可以在一个使用某种计数器计算它的函数中修饰它。实施示例:

更新:我已经更改了答案,但旧答案保留在答案的最后 //更新

这里假设你在some_module.py中有一些递归函数:

# From some_module.py
def factorial(x):
    return factorial(x-1)*x if x > 1 else 1

def cumsum(x):
    return cumsum(x-1) + x if x > 1 else 1

def loopBST(root):
    # ... your code

并且您想要应用装饰器来计算运行的递归次数。这里,代码在some_function()内执行,表明您不必将计数变量保留在全局范围内。 (参见注释)(此外,递归函数仍在全局空间中)

# Main file:
from functools import wraps, partial
from collections import defaultdict
# import the two recursion functions from some_module.py
from some_module import cumsum, factorial, loopBST


def some_function():
    global factorial, cumsum, loopBST

    def counting_recursion(fn, counter):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            counter[fn.__name__] += 1
            return fn(*args, **kwargs)
        return wrapper

    counters = defaultdict(int)

    my_deco = partial(counting_recursion, counter=counters)
    factorial = my_deco(factorial)
    cumsum = my_deco(cumsum)
    loopBST = my_deco(loopBST)

    print(factorial(3))
    # 6
    print(cumsum(5))
    # 15

    factorial_count = counters[factorial.__name__]
    cumsum_count = counters[cumsum.__name__]
    loopBST_count = counters[loopBST.__name__]  # Equals 0: were not called in my example

    print('The "{}" function ran {} times'.format(factorial.__name__, factorial_count))
    print('The "{}" function ran {} times'.format(cumsum.__name__, cumsum_count))
    # The "factorial" function ran 3 times
    # The "cumsum" function ran 5 times

一些修改/变化:

可以直接修饰递归函数,而不是使用my_deco = partial(counting_recursion, counter=counters)

cumsum = counting_recursion(cumsum, counter=counters)
factorial = counting_recursion(factorial, counter=counters)
loopBST = counting_recursion(loopBST, counter=counters)

而不是使用fn.__name__来识别被调用的函数,counting_recursion - 函数可以重写为:

def counting_recursion(fn, counter):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        counter[wrapper] += 1
        return fn(*args, **kwargs)
    return wrapper

然后,从counters字典中读取数字:

factorial_count = counters[factorial]
cumsum_count = counters[cumsum]
loopBST_count = counters[loopBST]

如果您想了解有关包装功能的更多信息,请查看https://stackoverflow.com/a/25827070/1144382以及wraps上的文档

旧例子:

from functools import wraps, partial

class Counter:
    def __init__(self, start_count=0):
        self._counter = start_count

    def __repr__(self):
        return str(self._counter)

    def count(self):
        self._counter += 1

counter = Counter()

def counting_recursion(fn, counter):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        counter.count()
        return fn(*args, **kwargs)
    return wrapper

my_deco = partial(counting_recursion, counter=counter)

@my_deco
def factorial(x):
    return factorial(x-1)*x if x > 1 else 1

print(factorial(3))
# 6

print('The {} function ran {} times'.format(factorial.__name__, counter))
# The factorial function ran 3 times

要在你的情况下实现这一点,只需制作一些计数器并装饰你的功能:

@my_deco
def loopBST(root):
    # ...

print(counter._counter)
# prints number of counts

当然,你不必让Counter - 类来打电话给counter.count(),你也可以有一个计数器字典,例如counts[loopBST] += 1或仅包含单个元素count_list[0] += 1的数组。 (请参阅本答案顶部的代码示例)(整个要点是“隐藏”重新分配变量时未重写的引用中的值,这就是整数计数的原因{ {1}}无效。)

答案 3 :(得分:0)

也许你可以尝试使用类的实例,这样它可能比使用关键字参数更干净。更不用说您可以在实例中存储其他数据。

这是一个Python 2.7类。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img id="images"/>