我正在学习拓扑排序和图表。我在下面使用DFS实现了一个版本,但是我无法理解为什么维基百科页面说这是O(| V | + | E |)并分析它的时间复杂度,以及| V | + | E |之间的差异。和n ^ 2一般。
首先,我有两个for循环,逻辑说它会是(n ^ 2)但是在任何DAG(或树)中都有n-1个边和n个顶点?如果我们可以删除" -1"这与n ^ 2有何不同?没有重要价值?
graph = {
1:[4, 5, 7],
2:[3,5,6],
3:[4],
4:[5],
5:[6,7],
6:[7],
7:[]
}
from collections import defaultdict
def topological_sort(graph):
ordered, marked = [], defaultdict(int)
while len(ordered) < len(graph):
for vertex in graph:
if marked[vertex]==0:
visit(graph, vertex, ordered, marked)
return ordered
def visit(graph, n, ordered, marked):
if marked[n] == 1:
raise 'Not a DAG'
marked[n] = 1
for neighbor in graph.get(n):
if marked[neighbor]!=2:
visit(graph, neighbor, ordered, marked)
marked[n] = 2
ordered.insert(0, n)
def main():
print(topological_sort(graph))
main()
答案 0 :(得分:1)
正确的实现在O(|V| + |E|)
时间内有效,因为它最多遍历每个边缘和每个顶点一次。对于完整(或几乎完整的图表),它与O(|V|^2)
相同。但是,当图形稀疏时,它会好得多。
您的实施是O(|V|^2)
,而不是O(|V| + |E|)
。这两个嵌套循环:
while len(ordered) < len(graph):
for vertex in graph:
if marked[vertex]==0:
visit(graph, vertex, ordered, marked)
在最糟糕的情况下进行1 + 2 ... + |V| = O(|V|^2)
次迭代(例如,对于空图)。你可以通过摆脱外循环轻松修复(它很简单:只需删除while循环。你不需要它。)