遍历由其边缘表示的树

时间:2015-12-07 20:09:16

标签: java algorithm tree time-complexity depth-first-search

我的树由其边和根节点表示。边缘列表是无向

char[][] edges =new char[][]{
    new char[]{'D','B'},
    new char[]{'A','C'},
    new char[]{'B','A'}             
};

char root='A';

树是

  A
 B  C
D

如何在此树上进行深度优先遍历?什么是时间复杂度?

我知道链接节点上深度优先遍历的时间复杂度是O(n)。但是如果树由边缘表示,我觉得时间复杂度是O(n ^ 2)。我错了吗?

感谢代码,虽然我知道它看起来像家庭作业..

1 个答案:

答案 0 :(得分:3)

DFS背后的通用模板如下所示:

 function DFS(node) {
     if (!node.visited) {
         node.visited = true;
         for (each edge {node, v}) {
             DFS(v);
         }
     }
 }

如果将边缘表示为图形中所有边的列表,则可以通过迭代图中的所有边来实现for循环,并且每次找到以当前节点为源的边时,跟随其端点的边缘并从那里运行DFS。如果你这样做,那么你将在图中的每个节点做O(m)工作(这里,m是边数),所以运行时将是O(mn),因为你最多只做一次图中的每个节点。在树中,边数始终为O(n),因此对于树,运行时为O(n 2 )。

也就是说,如果你有一棵树并且只有n个边缘,你可以通过多种方式加快速度。首先,您可以考虑执行O(n log n)预处理步骤来对边数组进行排序。然后,您可以通过二进制搜索找到离开给定节点的所有边,找到离开节点的第一条边,然后从边开始迭代,找到离开节点的边。这大大改善了运行时间:您为每个节点执行O(log n)工作以进行二进制搜索,然后每个边缘只访问一次。这意味着运行时为O(n log n)。由于你已经提到边缘是无向的,你实际上需要创建两个不同的边缘数组副本 - 一个是原始的,另一个是边缘相反的 - 并且应该独立地对每一个进行排序。事实上,DFS标记了沿途访问的节点,这意味着您不需要在此处进行任何额外的簿记,以确定每个步骤应该采用哪个方向,这并不会改变整体时间复杂度,尽管它确实会增加空间使用。

或者,您可以使用基于散列的解决方案。在执行DFS之前,迭代边缘并将它们转换为哈希表,其密钥是节点,其值是离开该节点的边的列表。这将花费预期时间O(n)。然后,您可以通过执行哈希表查找来查找有问题的边缘,从而非常有效地实现“for each edge”步骤。这减少了(预期)O(n)的时间,尽管空间使用也达到了O(n)。由于边缘是无向的,因此在填充表格时,只需确保在每个方向插入边缘。