经常有人说(例如,在Wikipedia中),图上的广度优先搜索(BFS)的运行时间为。但是,任何连接图都具有,即使在非连接图中,BFS也永远不会查看包含起始顶点的组件外部的顶点。该组件最多包含 边,所以它最多包含个顶点,这些是该算法将访问的唯一顶点。
这意味着,那么为什么不说运行时间仅为呢?
经常有人说(例如,在Wikipedia中),图上的广度优先搜索(BFS)的运行时间为。但是,任何连接图都具有,即使在非连接图中,BFS也永远不会查看包含起始顶点的组件外部的顶点。该组件最多包含 边,所以它最多包含个顶点,这些是该算法将访问的唯一顶点。
这意味着,那么为什么不说运行时间仅为呢?
Answers:
BFS通常描述如下(来自Wikipedia)。
1 procedure BFS(G,start_v):
2 let Q be a queue
3 label start_v as discovered
4 Q.enqueue(start_v)
5 while Q is not empty
6 v = Q.dequeue()
7 if v is the goal:
8 return v
9 for all edges from v to w in G.adjacentEdges(v) do
10 if w is not labeled as discovered:
11 label w as discovered
12 w.parent = v
13 Q.enqueue(w)
这个问题有些微妙:它隐藏在第3行中!问题是,我们将使用什么数据结构来存储已发现的顶点?
最简单的解决方案是使用每个顶点只有一个条目的布尔数组。在这种情况下,我们必须将数组的每个元素初始化为false
,这需要时间。即使根本没有边,这也适用于每个图形,因此我们不能假定之间有任何关系和 并且我们得到的运行时间为。
我们可以避免使用具有初始化时间的数据结构吗?我们的第一个尝试可能是使用链接列表。但是,现在测试是否已发现顶点(第10行)所花费的时间与所访问的顶点数成线性关系,而不是像以前那样恒定的时间。这意味着运行时间变为,在最坏的情况下更糟。(请注意,我们不想将其重写为因为这更糟:它可能和一样糟糕,而)
使用动态调整大小的数组将使我们能够对列表进行排序,因此现在查找仅需要时间而运行时间仅为,仍然比标准差。
最后,我们可以使用动态大小的哈希表:从大小为的常量表开始, 并在每次填充一半时将其加倍。这意味着表的最终大小最多为算法终止前发现的顶点数量的两倍,并且最多为因为我们从不发现起始顶点组件之外的任何东西。此外,复制哈希表以对其进行扩展所完成的总工作量最多为。查找和插入到哈希表的摊销,所以我们确实获得的运行时间。
因此是可能的,但是否想在实际实现中做到这一点?我可能不会说。除非您有理由相信输入图将包含许多小组件,否则维护哈希表的开销将为运行时间增加一个明显的常数。增长哈希表可能需要花费时间并且查找将需要您计算哈希函数,并且平均而言,要查看表中的多个插槽。哈希表的缓存性能不佳也可能会损害您在真实计算机上的性能。在大多数情况下,使用标准数组实现,部分是的主导项 运行时间,考虑到这样做的实际成本,因此不值得使用哈希表来删除主导术语。