BFS和DFS的运行时间解释
为什么 BFS 和 DFS 的运行时间都是 O(V+E),特别是当有一个节点与从顶点可以到达的节点有有向边时,就像下面站点的这个例子
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/depthSearch.htm
Why are the running times of BFS and DFS O(V+E), especially when there is a node that has a directed edge to a node that can be reached from the vertex, like in this example in the following site
http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/depthSearch.htm
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
E是图中所有边的集合,如G={V,E}。所以,|E|是图中所有边的计数。
仅此一点就足以让您相信整体复杂性不可能是 |V|次|E|,因为我们没有迭代图中每个顶点的所有边。
在邻接表表示中,对于每个顶点v,我们只遍历与其相邻的那些节点。
|V| |V|+|E| 的因子似乎来自完成的队列操作的数量。
请注意,算法的复杂性取决于所使用的数据结构。
实际上,我们正在访问图形表示中存在的每条信息,这就是为什么对于图形的矩阵表示,复杂性变为 V 平方。
引用科门的话,
E is the set of all edges in the graph, as G={V,E}. So, |E| is count of all edges in the graph.
This alone should be enough to convince you that the overall complexity can't be |V| times |E|, since we are not iterating over all the edges in the graph for each vertex.
In the adjacency list representation, for each vertex v, we only traverse those nodes which are adjacent to it.
The |V| factor of the |V|+|E| seems to come from the number of queue operations done.
Note that the complexity of the algorithm depends on the data structure used.
effectively we are visiting each piece of information present in the representation of the graph, which is why for matrix representation of the graph, complexity becomes V squared.
Quoting from Cormen,
这个问题花了我大约 4 个小时的时间,但最后,我想我有一个简单的方法来获得图片,一开始我很想说 O ( V * E )。
总结一下您在 Cormen 中找到的算法,该算法与 上的算法相同http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/breadthSearch.htm 你有像这样:
问题是这里执行了多少条指令?这将是 Sigma-Sum (Adj(vi)),并且该值的上限为 2|E|。
一开始,我们会自动考虑将内循环和外循环的迭代次数相乘,但在这种情况下,内循环的迭代总数是外迭代器的函数,因此不可能进行乘法。
This issue consumed like 4 hours of my time but finally, I think I have an easy way to get the picture, at the beginning I was tempted to say O ( V * E ).
Summarizing the algorithm that you find in Cormen, that is the same on http://www.personal.kent.edu/~rmuhamma/Algorithms/MyAlgorithms/GraphAlgor/breadthSearch.htm you have something like this :
The question is how many instructions are executed here? that will be the Sigma-Sum (Adj(vi)), and this value is upper-bounded by 2|E|.
In the beginning, we automatically think about multiplying the number of iterations of the inner and outer loops, but in this case, the total number of iterations on the inner loop is a function of the outer iterator, so no multiplication is possible.
您最多访问每个边两次。有E边。所以就会有2*E的边访问操作。加上那些没有边的节点,或者换句话说,度数为 0 的节点。最多可以有 V 个这样的节点。因此复杂度为 O(2*E + V) = O(E + V)
You visit every edge at most twice. There are E edges. So there will be 2*E edge visit operations. Plus the nodes those have no edges or in other words, with degree 0. There can be at most V such nodes. So the complexity turns out to be, O(2*E + V) = O(E + V)
当您将图形视为表示为相邻列表的数据结构时,它就会变得清晰
您会看到顶点:A、B、C、D、E 以及每个顶点/节点的相邻顶点作为这些顶点的列表。您必须“查看”所有框来检查它是否已被“访问”(如果是循环图),或者如果它是树状图,您只需遍历所有子项
It becomes clear when you see a graph as a data structure represented as an adjacent list
You see Vertices: A,B,C,D,E and adjacent vertices for each Vert/Node as list from those vert. You have to "see" all boxes to check wether it has been "visited" in case of cyclical graph or you just go through all children if it's tree like graph
您迭代 |V|节点,最多 |V|次。因为我们有一个上限 |E|图中的边总数,我们最多检查 |E|边缘。不同的顶点将具有不同数量的相邻节点,因此我们不能只将 |V|*|E| 相乘(这意味着对于每个顶点,我们遍历|E|边,这是不正确的,|E|是所有节点上的边总数),相反,我们检查V个节点,并且我们检查总共E个边缘。最后,我们有 O(|V|+|E|)
对于 DFS,它是类似的东西,我们循环遍历所有顶点邻接列表,如果没有被访问过,则调用 DFS(v),这意味着我们会产生 |V |时间步长,加上访问相邻节点所花费的时间(本质上,这些形成一条边,我们总共有 |E| 条边,因此,时间为 O(V+E)。
You iterate over the |V| nodes, for at most |V| times. Since we have an upper bound of |E| edges in total in the graph, we will check at most |E| edges. Different vertices will have varying number of adjacent nodes, so we cannot just multiply |V|*|E| (it means that for each vertex, we traverse |E| edges, which is not true, |E| is the total number of edges over all nodes), rather, we check over V nodes, and we check over a total of E edges. At the end, we have O(|V|+|E|)
For DFS, it's something similar, we loop through all of a vertices adjacency lists, calling DFS(v) if it's not been visited, meaning that we incur |V| time steps, plus the time incurred to visit adjacent nodes (essentially, these form an edge, and we have a total of |E| edges, hence, O(V+E) time.