📜  图的拓扑排序使用顶点的离开时间

📅  最后修改于: 2022-05-13 01:57:53.868000             🧑  作者: Mango

图的拓扑排序使用顶点的离开时间

给定一个有向无环图(DAG),求该图的拓扑排序。
有向无环图 (DAG) 的拓扑排序是顶点的线性排序,因此对于每个有向边 uv,顶点 u 在排序中位于 v 之前。如果图不是 DAG,则无法对图进行拓扑排序。
例如,下图的拓扑排序是“5 4 2 3 1 0”。一个图可以有多个拓扑排序。例如,下图的另一种拓扑排序是“4 5 2 3 1 0”。

拓扑排序

请注意,拓扑排序中的第一个顶点始终是入度为 0 的顶点(没有传入边的顶点)。对于上图,顶点 4 和 5 没有传入边。

我们已经讨论了使用堆栈和卡恩拓扑排序算法的基于 DFS 的算法。我们还讨论了如何在这里打印所有拓扑类型的 DAG。在这篇文章中,通过在 DFS 中引入顶点的到达和离开时间的概念,讨论了另一种基于 DFS 的方法来查找图的拓扑排序。

DFS中顶点的到达时间和离开时间是什么?
在 DFS 中, Arrival Time是第一次探索顶点的时间, Departure Time是我们已经探索了顶点的所有邻居并准备回溯的时间。

如何使用出发时间找到图的拓扑排序?
为了找到图的拓扑排序,我们从所有未访问的顶点一个接一个地运行 DFS。对于任何顶点,在探索其任何邻居之前,我们记录该顶点的到达时间,在探索该顶点的所有邻居之后,我们记录其离开时间。请注意,查找图的拓扑排序只需要出发时间,因此我们可以跳过顶点的到达时间。最后,在我们访问了图的所有顶点之后,我们按照出发时间递减的顺序打印顶点,这就是我们想要的顶点拓扑顺序。
下面是上述想法的 C++ 实现——

C++
// A C++ program to print topological sorting of a DAG
#include 
using namespace std;
 
// Graph class represents a directed graph using adjacency
// list representation
class Graph {
    int V; // No. of vertices
    // Pointer to an array containing adjacency lists
    list* adj;
 
public:
    Graph(int); // Constructor
    ~Graph(); // Destructor
 
    // function to add an edge to graph
    void addEdge(int, int);
 
    // The function to do DFS traversal
    void DFS(int, vector&, vector&, int&);
 
    // The function to do Topological Sort.
    void topologicalSort();
};
 
Graph::Graph(int V)
{
    this->V = V;
    this->adj = new list[V];
}
 
Graph::~Graph() { delete[] this->adj; }
 
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); // Add w to v's list.
}
 
// The function to do DFS() and stores departure time
// of all vertex
void Graph::DFS(int v, vector& visited,
                vector& departure, int& time)
{
    visited[v] = true;
    // time++;    // arrival time of vertex v
 
    for (int i : adj[v])
        if (!visited[i])
            DFS(i, visited, departure, time);
 
    // set departure time of vertex v
    departure[time++] = v;
}
 
// The function to do Topological Sort. It uses DFS().
void Graph::topologicalSort()
{
    // vector to store departure time of vertex.
    vector departure(V, -1);
 
    // Mark all the vertices as not visited
    vector visited(V, false);
    int time = 0;
 
    // perform DFS on all unvisited vertices
    for (int i = 0; i < V; i++) {
        if (visited[i] == 0) {
            DFS(i, visited, departure, time);
        }
    }
    // print the topological sort
    for (int i = V - 1; i >= 0; i--)
        cout << departure[i] << " ";
}
 
// Driver program to test above functions
int main()
{
    // Create a graph given in the above diagram
    Graph g(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);
 
    cout << "Topological Sort of the given graph is \n";
    g.topologicalSort();
 
    return 0;
}


Python3
# A Python3 program to print topological sorting of a DAG
def addEdge(u, v):
    global adj
    adj[u].append(v)
 
# The function to do DFS() and stores departure time
# of all vertex
def DFS(v):
    global visited, departure, time
    visited[v] = 1
    for i in adj[v]:
        if visited[i] == 0:
            DFS(i)
    departure[time] = v
    time += 1
 
# The function to do Topological Sort. It uses DFS().
def topologicalSort():
 
    # perform DFS on all unvisited vertices
    for i in range(V):
        if(visited[i] == 0):
            DFS(i)
 
    # Print vertices in topological order
    for i in range(V - 1, -1, -1):
        print(departure[i], end = " ")
 
# Driver code
if __name__ == '__main__':
   
    # Create a graph given in the above diagram
    V,time, adj, visited, departure = 6, 0, [[] for i in range(7)], [0 for i in range(7)],[-1 for i in range(7)]
    addEdge(5, 2)
    addEdge(5, 0)
    addEdge(4, 0)
    addEdge(4, 1)
    addEdge(2, 3)
    addEdge(3, 1)
 
    print("Topological Sort of the given graph is")
    topologicalSort()
 
# This code is contributed by mohit kumar 29


Javascript


输出
Topological Sort of the given graph is 
5 4 2 3 1 0 

上述解决方案的时间复杂度为 O(V + E)。