圖解拓撲排序(Topological sort)
阿新 • • 發佈:2018-12-17
一、什麼是拓撲排序
下圖就是拓撲排序
拓撲排序其實是一個線性排序。——若圖中存在一條有向邊從u指向v,則在拓撲排序中u一定出現在v前面。
a topological sort or topological ordering of a directed graph is a linear ordering of its vertices such that for every directed edge uv
二、圖解拓撲排序
演算法思路:
1. 從圖中選擇一個沒有前驅(即入度為0)的頂點並輸出。
2. 從圖中刪除該頂點和所有以它為起點的有向邊。
重複 1 和 2 直到圖為空或當前圖中不存在無前驅的頂點為止。
偽碼:
例子:
. 1. 選入度為0的節點A, 輸出A。 刪除AB AC的邊(B入度為1-1=0,C入度為2-1=1)
2. 選入度為0的節點B, 輸出B。刪除BC,BE的邊(C入度為1-1=0,E入度-1)
3. 選入度為0的節點C, 輸出C。刪以C開始的邊(對應節點入度-1)
。。。。。。。。。。。繼續重複。。。。。。。。。。
注: 拓撲排序結果不唯一(同時有多個入度為0)。
三、Code in Java
import java.util.*; // data structure to store graph edges class Edge { int source, dest; public Edge(int source, int dest) { this.source = source; this.dest = dest; } }; // class to represent a graph object class Graph { // An array of Lists to represent adjacency list List<List<Integer>> adjList = null; // stores indegree of a vertex List<Integer> indegree = null; // Constructor Graph(List<Edge> edges, int N) { adjList = new ArrayList<>(N); for (int i = 0; i < N; i++) { adjList.add(i, new ArrayList<>()); } // initialize indegree of each vertex by 0 indegree = new ArrayList<>(Collections.nCopies(N, 0)); // add edges to the undirected graph for (int i = 0; i < edges.size(); i++) { int src = edges.get(i).source; int dest = edges.get(i).dest; // add an edge from source to destination adjList.get(src).add(dest); // increment in-degree of destination vertex by 1 indegree.set(dest, indegree.get(dest) + 1); } } } class Main { // performs Topological Sort on a given DAG public static List<Integer> doTopologicalSort(Graph graph, int N) { // list to store the sorted elements List<Integer> L = new ArrayList<>(); // get indegree information of the graph List<Integer> indegree = graph.indegree; // Set of all nodes with no incoming edges Stack<Integer> S = new Stack<>(); for (int i = 0; i < N; i++) { if (indegree.get(i) == 0) { S.add(i); } } while (!S.isEmpty()) { // remove a node n from S int n = S.pop(); // add n to tail of L L.add(n); for (int m : graph.adjList.get(n)) { // remove edge from n to m from the graph indegree.set(m, indegree.get(m) - 1); // if m has no other incoming edges then // insert m into S if (indegree.get(m) == 0) { S.add(m); } } } // if graph has edges then graph has at least one cycle for (int i = 0; i < N; i++) { if (indegree.get(i) != 0) { return null; } } return L; } public static void main(String[] args) { // vector of graph edges as per above diagram List<Edge> edges = Arrays.asList( new Edge(0, 6), new Edge(1, 2), new Edge(1, 4), new Edge(1, 6), new Edge(3, 0), new Edge(3, 4), new Edge(5, 1), new Edge(7, 0), new Edge(7, 1) ); // Set number of vertices in the graph final int N = 8; // create a graph from edges Graph graph = new Graph(edges, N); // Perform Topological Sort List<Integer> L = doTopologicalSort(graph, N); if (L != null) { System.out.print(L); // print topological order } else { System.out.println("Graph has at least one cycle. " + "Topological sorting is not possible"); } } }
四、演算法分析
時間複雜度: O(n + e)
,其中n
為圖中的結點數目,e
為圖中的邊的數目
空間複雜度:O(n)
也可以用深度優先遍歷DFS和 廣度優先遍歷BFS 實現拓撲排序。