Because when used for topological sort you do a DFS on every nodes. If one of the children is already visited by a previous DFS (colored black). Then it is already pushed in the output vector and so you the dependency is already done.
Quoting your link (emphasis mine):
The algorithm loops through each node of the graph, in an arbitrary order, initiating a depth-first search ...
As the wikipedia article is a bit confusing (in my opinion) I will try to better describe the algorithm:
V: set of vertices
E: set of edges
E.adj(v): set of vertices adjacent to vertex v
0 function topological_sort(V,E):
1 for v in V:
2 paint v white
3
4 for v in V:
5 if v is white:
6 dfs(v)
7 function dfs(v):
8 paint v grey
9 for child in E.adj(v)
10 if child is white:
11 dfs(child)
12 paint v black
13 push v to output
We can easily compute the complexity:
- We paint a vertex white, grey and black once per vertex:
O(V)
- We check the color of the vertex at line
5
once per vertex: O(V)
- We check the color of the vertex at line
10
once per edge: O(E)
- We push the vertex to output at line
13
once per vertex: O(V)
So the final complexity is: O(V+E)
. It is pretty efficient.
One of the strength of this algorithm is that it doesn't need to modify the input graph. We can easily implement coloring by a temporary hashtable with a size in O(V)
. Some other topological sort algorithm requires to destroy the graph when they proceed (by removing edges). This would require to copy the graph before running the toplogical sort if you still need the graph after the sort.