圖拓撲排序的兩種方法實現
阿新 • • 發佈:2019-01-31
方法一:
(1)在有向圖中選一個沒有前驅(入度為0)的點輸出。
(2)從圖中刪除該頂點和所有以它為尾的弧。
重複以上步驟,直至全部頂點均已輸出,或者當前圖中不存在五前驅的頂點為止。
在實現中,我們可以用一個佇列存入所有入度為0的頂點。然後依次刪除這些頂點,和其對應的邊,如果對應邊刪除後其終點的入度減為0者也將其存入佇列中,如此迴圈下去,直到佇列為空。最後比較列表中的節點數是否等於圖的頂點數,如果不等者圖存在一個環。
基於以上的規則可以用下面的程式碼來實現圖的拓撲排序。
Java程式碼- /**
- * 圖的拓撲排序2,該方法會改變圖的結構
-
* @param <T>
- * @return
- */
- public static<T> List<T> topologicalSort2(Graph<T> graph){
- Queue<T> vQueue = new LinkedList<T>();
- List<T> vList = new ArrayList<T>();
- Set<T> vSet = graph.vertexSet();
-
Set<T> neighbors = null
- T vertex = null;
- //將入度為0的節點存入佇列中
- for(T v : vSet){
- if(graph.getIndegree(v) == 0){
- vQueue.add(v);
- vList.add(v);
- }
- }
- while(!vQueue.isEmpty()){
- vertex = vQueue.poll();
-
neighbors = graph.getNeighbors(vertex);
- for(T neighbor : neighbors){
- graph.removeEdge(vertex, neighbor);//刪除該邊
- if(graph.getIndegree(neighbor) == 0){//若neighbor的入度變為0,者也將其加入佇列中
- vQueue.add(neighbor);
- vList.add(neighbor);
- }
- }
- }
- if(vList.size() != graph.numberOfVertices()){
- throw new IllegalStateException("存在環");
- }
- return vList;
- }
方法二:
可以證明在被路徑p(v,w)連線的任意頂點所在的圖中,對於v和w來說,v在列表中必須出現在w之前。
依據這個結論可以對圖的每個節點進行一個dfs的遍歷,最終的節點列表就是拓撲排序的一個結果(要對這個列表反轉).
Java程式碼- /**
- * 圖的拓撲排序
- * @param <T>
- * @param graph
- * @return
- */
- public static<T> List<T> topologicalSort(Graph<T> graph){
- List<T> vList = new ArrayList<T>();
- graph.allUnVisted();
- for(T v : graph.vertexSet()){
- if(graph.getState(v) == VertexState.UNVISITED){
- try{
- dfsHandler(graph, v, true, vList);
- }catch (IllegalStateException e) {
- throw new IllegalStateException("圖有一個環");
- }
- }
- }
- Collections.reverse(vList);
- return vList;
- }
測試:
針對下面這個圖進行測試
/**
- * 測試圖的拓撲排序
- */
- public void testTopologicalSort(){
- List<String> vList = GraphUtil.topologicalSort(graph);
- System.out.println(Arrays.toString(vList.toArray()));
- vList = GraphUtil.topologicalSort2(graph);
- System.out.println(Arrays.toString(vList.toArray()));
- }
Output:
[c2, c5, c1, c3, c7, c6, c4, c8]
[c1, c2, c3, c5, c4, c6, c7, c8]