我在树上有一个简单的递归后序遍历,可以打印所有可能的路径。问题是需要花费很多时间。
我想使用树的属性来节省遍历时间。 属性是我有重复的子树,在下面的例子中,头1的子树出现在树中3次。
10
/ | \
5 15 1
/\ / \ / \
2 1 1 6 3 8
/ \ / \
3 8 3 8
我寻找改进我的遍历,跳过已经通过的子树。 我的想法是存储我已经通过的每个子树,但我无法将其与后序算法相匹配。
感谢您的帮助。
答案 0 :(得分:1)
使用哈希集来存储已访问过的节点,并且对于您访问的每个节点,检查它是否已被访问过:如果没有,请将其添加到访问集,然后照常继续,否则返回。
答案 1 :(得分:0)
我不知道你的程序是否允许这种改变....因为我们无法知道在遍历之前是否出现了一个子树,一种可能的方法是按照以下方式重新组织树以共享重复的子树。
10
/ | \
5 15 1
/\ / \ / \
2 1 ------ 6 3 8
/ \
3 8
答案 2 :(得分:0)
打印所有可能的路径
我认为这是主要问题。程序的运行时间与要输出的数据量呈线性关系,大致对于程序执行的树中的每一步,它应输出至少一个符号。只要你保持所需的输出相同(即只要你需要输出所有路径),你就没有加速的空间了,你就不能拥有比O(R)
更快的算法,其中R
是您需要生成的输出的总大小。
事实上,很可能主要的瓶颈是输出本身(控制台或磁盘性能通常比仅仅在内存中行走更糟),所以我认为如果你对程序进行分析,你会发现90%的时间花在了在输出中。因此,不仅无法获得更好的渐近解决方案,也无法获得更快的解决方案。 (除非您优化输出本身,但这是一个不同的问题。)
但是,如果您不需要打印所有路径,但以某种方式处理它们 - 例如,计算它们存在多少,或找到最长路径等 - 那么您的解决方案你可以从重复的子树中获益。实际上,这意味着您没有树,而是有向无环图,这通常允许使用相当简单的动态编程方法。
答案 3 :(得分:0)
假设每个节点代表一个以该节点为根的唯一子树,并且节点值集不是很大,您可以使用它来优化遍历:
string s[MAX_NODE_VALUE + 1];
string post_traverse(Node root)
{
if(root == NULL)
return "";
if(s[root.value].length() == 0)
{
s[root.value] += post_traverse(root.left);
s[root.value] += post_traverse(root.right);
s[root.value] += itoa(root.value);
s[root.value] += ' ';
}
cout << s[root.value];
return s[root.value];
}
这只会在你有太多的重复子树和节点值集非常小时才有用,否则会消耗太多空间并花费更多时间。