通常在解决递归或动态编程问题时,我发现自己正在绘制一棵递归树来帮助简化我的问题。但是,对于一些复杂的问题,我可以使用该解决方案,但不知道如何绘制树。
到目前为止,我一直在尝试打印出调用函数及其参数,这在某些示例中被证明是有用的。但是,我看到了mathematica在以下答案中为fibonacci(5)生成的树:https://mathematica.stackexchange.com/questions/116344/how-do-i-create-a-recursive-tree-plot-for-the-fibonacci-sequence
我想知道是否可以用主流的高级语言(例如Python,Java或C ++)生成相同类型的树?树可能只是像图像中那样具有节点作为函数名称和参数。
答案 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 。 这是输出动画的外观: 也是递归树的最终图像:
我们还可以使用节点颜色和其他属性使其更好:
# 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()
这是看起来更好的输出:
这是递归树的最终图像:
在here上查看更多示例
答案 1 :(得分:1)
这里是一个例子:
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
制作:
这比所请求的图像更紧凑,在该图像中,具有相同值的重复调用由一个节点表示,并且如果存在从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";
}