生成通用递归程序的递归树的程序

时间:2019-03-07 07:29:07

标签: java c++ recursion visualization

通常在解决递归或动态编程问题时,我发现自己正在绘制一棵递归树来帮助简化我的问题。但是,对于一些复杂的问题,我可以使用该解决方案,但不知道如何绘制树。

到目前为止,我一直在尝试打印出调用函数及其参数,这在某些示例中被证明是有用的。但是,我看到了mathematica在以下答案中为fibonacci(5)生成的树:https://mathematica.stackexchange.com/questions/116344/how-do-i-create-a-recursive-tree-plot-for-the-fibonacci-sequence

enter image description here

我想知道是否可以用主流的高级语言(例如Python,Java或C ++)生成相同类型的树?树可能只是像图像中那样具有节点作为函数名称和参数。

2 个答案:

答案 0 :(得分:3)

我制作了一个名为recursion-visualiser的简单python程序包,您可以通过pip安装该程序包,该程序包可帮助您轻松跟踪任何任意递归函数的函数调用,并只需向其中添加装饰器即可将树另存为gif和png图像您的功能。

让我们为递归斐波那契函数绘制树。 这是递归代码:

def fib(n):
    if n <= 1:
        return n
    return fib(n=n - 1) + fib(n=n - 2)

def main():
    # Call function
    print(fib(n=6))

if __name__ == "__main__":
    main()

现在让我们修改代码以绘制递归树。首先让我们画一个非常简单的例子

# Import Visualiser class from module visualiser
from visualiser.visualiser import Visualiser as vs

# Add decorator
@vs()
def fib(n):
    if n <= 1:
        return n
    return fib(n=n - 1) + fib(n=n-2)

def main():
    print(fib(n=6))
    vs.make_animation("fibonacci.gif", delay=2)

if __name__ == "__main__":
    main()

输出文件另存为 fibonacci.gif fibonacci.png 。 这是输出动画的外观: Animation.gif 也是递归树的最终图像: tree.png

我们还可以使用节点颜色和其他属性使其更好:

# Import Visualiser class from module visualiser
from visualiser.visualiser import Visualiser as vs

# Add decorator
@vs(node_properties_kwargs={"shape":"record", "color":"#f57542", "style":"filled", "fillcolor":"grey"})
def fib(n):
    if n <= 1:
        return n
    return fib(n=n - 1) + fib(n=n-2)

def main():
    print(fib(n=6))
    vs.make_animation("fibonacci.gif", delay=2)

if __name__ == "__main__":
    main()

这是看起来更好的输出: animation.gif

这是递归树的最终图像: out.png

here上查看更多示例

答案 1 :(得分:1)

看看graphvizexamples of usage

这里是一个例子:

long long fib(int n)
{
    if (n <= 1) return 1;
    std::cout << "fib" << n << " -> fib" << n-2 << '\n';
    std::cout << "fib" << n << " -> fib" << n-1 << '\n';
    return fib(n-2) + fib(n-1);
}

int main()
{
    std::cout << "digraph {\n";
    fib(5);
    std::cout << "}\n";
}

运行

program > t.dot 
dot -Tpng t.dot

制作:

enter image description here

这比所请求的图像更紧凑,在该图像中,具有相同值的重复调用由一个节点表示,并且如果存在从fib(u)到fib(v)的N个调用,则节点u,v之间的N条边。 / p>

要获得一棵树,必须为每个调用维护唯一的ID。这是一个示例:

static unsigned id = 0;
long long fib(int n)
{
    auto call_id = id++;
    std::cout << "fib" << call_id << " [label=\"fib(" << n << ")\"]\n";
    if (n <= 1) return 1;
    std::cout << "fib" << call_id << " -> fib" << id << '\n';
    auto fib_n_minus_2 = fib(n-2);
    std::cout << "fib" << call_id << " -> fib" << id << '\n';
    auto fib_n_minus_1 = fib(n-1);
    return fib_n_minus_2 + fib_n_minus_1;
}

int main()
{
    std::cout << "digraph {\n";
    fib(5);
    std::cout << "}\n";
}

图为: enter image description here