1. 程式人生 > >圖拓撲排序的兩種方法實現

圖拓撲排序的兩種方法實現

方法一:

(1)在有向圖中選一個沒有前驅(入度為0)的點輸出。

(2)從圖中刪除該頂點和所有以它為尾的弧。

重複以上步驟,直至全部頂點均已輸出,或者當前圖中不存在五前驅的頂點為止。

在實現中,我們可以用一個佇列存入所有入度為0的頂點。然後依次刪除這些頂點,和其對應的邊,如果對應邊刪除後其終點的入度減為0者也將其存入佇列中,如此迴圈下去,直到佇列為空。最後比較列表中的節點數是否等於圖的頂點數,如果不等者圖存在一個環。

基於以上的規則可以用下面的程式碼來實現圖的拓撲排序。

Java程式碼  收藏程式碼
  1. /** 
  2.      * 圖的拓撲排序2,該方法會改變圖的結構 
  3.      * @param <T>
     
  4.      * @return 
  5.      */  
  6.     public static<T> List<T> topologicalSort2(Graph<T> graph){  
  7.         Queue<T> vQueue = new LinkedList<T>();  
  8.         List<T> vList = new ArrayList<T>();  
  9.         Set<T> vSet = graph.vertexSet();  
  10.         Set<T> neighbors = null
    ;  
  11.         T vertex = null;  
  12.         //將入度為0的節點存入佇列中  
  13.         for(T v : vSet){  
  14.             if(graph.getIndegree(v) == 0){  
  15.                 vQueue.add(v);  
  16.                 vList.add(v);  
  17.             }  
  18.         }  
  19.         while(!vQueue.isEmpty()){  
  20.             vertex = vQueue.poll();  
  21.             neighbors = graph.getNeighbors(vertex);  
  22.             for(T neighbor : neighbors){  
  23.                 graph.removeEdge(vertex, neighbor);//刪除該邊  
  24.                 if(graph.getIndegree(neighbor) == 0){//若neighbor的入度變為0,者也將其加入佇列中  
  25.                     vQueue.add(neighbor);  
  26.                     vList.add(neighbor);  
  27.                 }  
  28.             }  
  29.         }  
  30.         if(vList.size() != graph.numberOfVertices()){  
  31.             throw new IllegalStateException("存在環");  
  32.         }  
  33.         return vList;  
  34.     }  

 方法二:

可以證明在被路徑p(v,w)連線的任意頂點所在的圖中,對於v和w來說,v在列表中必須出現在w之前。

依據這個結論可以對圖的每個節點進行一個dfs的遍歷,最終的節點列表就是拓撲排序的一個結果(要對這個列表反轉).

Java程式碼  收藏程式碼
  1. /** 
  2.      * 圖的拓撲排序 
  3.      * @param <T> 
  4.      * @param graph 
  5.      * @return 
  6.      */  
  7.     public static<T> List<T> topologicalSort(Graph<T> graph){  
  8.         List<T> vList = new ArrayList<T>();  
  9.         graph.allUnVisted();  
  10.         for(T v : graph.vertexSet()){  
  11.             if(graph.getState(v) == VertexState.UNVISITED){  
  12.                 try{  
  13.                     dfsHandler(graph, v, true, vList);  
  14.                 }catch (IllegalStateException e) {  
  15.                     throw new IllegalStateException("圖有一個環");  
  16.                 }  
  17.             }  
  18.         }  
  19.         Collections.reverse(vList);  
  20.         return vList;  
  21.     }  

 測試:

針對下面這個圖進行測試



 /**

Java程式碼  收藏程式碼
  1.  * 測試圖的拓撲排序  
  2.  */  
  3. public void testTopologicalSort(){  
  4.     List<String> vList = GraphUtil.topologicalSort(graph);  
  5.     System.out.println(Arrays.toString(vList.toArray()));  
  6.     vList = GraphUtil.topologicalSort2(graph);  
  7.     System.out.println(Arrays.toString(vList.toArray()));  
  8. }  

 Output:

[c2, c5, c1, c3, c7, c6, c4, c8]

[c1, c2, c3, c5, c4, c6, c7, c8]