为什么BFS和DFS O(V + E)的运行时间,特别是当有一个节点具有可以从顶点到达的节点的有向边时,就像在以下站点中的此示例中一样< / p>
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/depthSearch.htm
答案 0 :(得分:40)
E是图中所有边的集合,如G = {V,E}。所以,| E |是图中所有边的计数。
仅此一点就足以让你相信整体复杂性不可能是| V | times | E |,因为我们没有迭代图中每个顶点的所有边。
在邻接列表表示中,对于每个顶点v,我们只遍历那些与它相邻的节点。
| V | | V | + | E |的因子似乎来自完成的队列操作次数。
请注意,算法的复杂性取决于所使用的数据结构。 实际上,我们正在访问图表表示中存在的每条信息,这就是为什么对于图表的矩阵表示,复杂度变为V平方。
来自Cormen,
“排队和出队的操作花费O(1)时间,因此用于队列操作的总时间是O(V)。因为每个顶点的邻接列表仅在顶点出列时被扫描,每个邻接列表最多扫描一次。由于所有邻接列表的长度之和为Θ(E),扫描邻接列表所花费的总时间为O(E)。初始化的开销为O(V),因此BFS的总运行时间为O(V + E)。“
答案 1 :(得分:18)
这个问题耗费了我4个小时的时间,但最后我觉得我有一个简单的方法来拍照,一开始我很想说O(V * E)。
总结在Cormen中找到的算法,http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/breadthSearch.htm上的算法是相同的,你有这样的东西:
for(vi in V) 一些O(1)指令 for(e in Adj(vi)) {一些O(1)指令 }
问题是这里执行了多少指令?这将是Sigma-Sum(Adj(vi)),并且该值上限为2 | E |。
一开始我们会自动考虑乘以内循环和外循环的迭代次数,但在这种情况下,内循环上的迭代总数是外迭代器的函数,因此不可能进行乘法运算。 / p>
答案 2 :(得分:8)
您最多访问每个边缘两次。有E边。因此将有2 * E边缘访问操作。加上那些没有边缘的节点,换句话说,有0度的节点。最多可以有V个这样的节点。因此复杂性证明是,O(2 * E + V)= O(E + V)
答案 3 :(得分:1)
当您将图形视为以相邻列表表示的数据结构时,这一点变得很清楚
您会看到顶点:每个Vert /节点的A,B,C,D,E和相邻顶点,作为这些顶点的列表。如果要使用周期性图,则必须“查看”所有框以检查它是否已被“访问”,或者如果它是树状图,则只需遍历所有子项
答案 4 :(得分:0)
你遍历| V |节点,最多为| V |倍。因为我们有| E |的上限在图中总共有边,我们最多检查| E |边缘。不同的顶点将具有不同数量的相邻节点,因此我们不能只需乘以| V | * | E | (这意味着对于每个顶点,我们遍历| E | edge,这不是真的,| E |是所有节点上的边的总数),而是我们检查V个节点,并检查总共E个边缘。最后,我们有O(| V | + | E |)
对于DFS,它是类似的东西,我们循环遍历所有顶点邻接列表,如果没有访问它则调用DFS(v),这意味着我们招致| V |时间步长,加上访问相邻节点所产生的时间(基本上,这些形成一个边,我们总共有| E |边,因此,O(V + E)时间。
private static void visitUsingDFS(Node startNode) {
if(startNode.visited){
return;
}
startNode.visited = true;
System.out.println("Visited "+startNode.data);
for(Node node: startNode.AdjacentNodes){
if(!node.visited){
visitUsingDFS(node);
}
}
}