2010-03-26 20 views
26

我們如何檢測有向圖是循環的?我想過使用廣度優先搜索,但我不確定。有任何想法嗎?如何檢測有向圖是循環的?

+0

可能重複[我怎樣檢查是否有向圖是無環?](http://stackoverflow.com/questions/583876/how- do-i-check-if-a-directed-graph-is-acyclic) – 2015-01-14 12:43:01

+0

我剛剛在相關的StackOverflow線程上發佈了Scala的通用FP解決方案:http://stackoverflow.com/a/36144158/501113 – chaotic3quilibrium 2016-03-22 00:43:29

回答

13

通常使用深度優先搜索來代替。 我不知道BFS是否適用。

DFS中,根據訪問順序構建生成樹。如果樹中的一個節點的祖先被訪問(即創建了一個後沿),那麼我們檢測到一個循環。

有關更詳細的解釋,請參閱http://www.cs.nyu.edu/courses/summer04/G22.1170-001/6a-Graphs-More.pdf

+1

BFS或DFS在這個問題上具有相同的複雜性(運行時)和適用性(相同的結果)。唯一的區別在於節點的訪問順序。 – darlinton 2010-03-26 17:46:26

+0

鏈接中指示的頁面上的最後一條語句是基於邊和頂點數的拓撲語句: 「圖G中沒有循環的最大可能邊數爲| V | -1。 「 對於*未定向*圖,對於*定向*圖,這是正確的,如原始問題所示。對於有向圖,「鑽石繼承」圖提供了一個反例(4個節點和4個邊形成一個「循環」,但不是可以通過跟隨箭頭遍歷的「循環」)。 – Peter 2010-03-29 16:49:32

+3

如果最後一條評論不清楚 - 我說接受的答案對於無向圖而言是足夠的,但對於有向圖而言是錯誤的*(如問題中指定的)。 – Peter 2010-03-29 18:44:42

-1

另一個簡單的解決方案是標記和掃描方法。基本上,對於樹中的每個節點,將其標記爲「已訪問」,然後轉到其子節點。如果你看到一個設置了「visted」標誌的節點,你就知道有一個循環。

如果修改圖形以包含「訪問」位是不可能的,則可以使用一組節點指針。要將節點標記爲已訪問,請在該集​​中放置一個指向它的指針。如果指針已經在集合中,就有一個循環。

+0

該解決方案與KennyTM提供的解決方案類似,但對問題更好。問題在於識別週期,所以標記和掃描是一種很好的方法。正如Kenny所建議的,構建生成樹是解決問題的一種更復雜的方法,因爲您正在使用生成樹的概念。最後,它幾乎都是一樣的。 – darlinton 2010-03-26 17:48:56

+3

@Rakis:它會誤認http://en.wikipedia.org/wiki/File:Diamond_inheritance.svg爲​​一個循環嗎? – kennytm 2010-03-26 18:26:26

+0

@KennyTM:是的,它會的。如果您使用DFS或BFS探索圖中的節點,則無關緊要 - 您將以同樣的方式得到相同的錯誤答案。跟蹤哪些節點已被訪問以識別週期是不夠的。所以我會從Rakis中扣除一點答案(但我的名聲太微不足道了)。 – Peter 2010-03-29 16:42:16

16

你真正需要的是什麼,我相信,在這裏所描述的一樣一個一個拓撲排序算法:

http://en.wikipedia.org/wiki/Topological_sorting

如果有向圖有一個週期,則算法將失敗。

的意見/回答說,我到目前爲止看到似乎缺少一個事實,即在定向圖可能有不止一種方法從節點X獲得,而不存在以節點Y的任何(導演)圖中的週期。

1

方法:1
如何檢測一個週期級別沒有分配。例如:考慮下面的圖表。 (B,C)B-> D D - >(E,F)E,F - >(G)E-> D當您執行DFS開始時,爲您訪問的節點分配一個級別no = 0)。級別no =父節點+ 1。所以A = 0,B = 1,D = 2,F = 3,G = 4,則遞歸達到D,所以E = 3。不要標記G的等級(G已經是一個沒有被分配的等級比E更高的等級)現在E也具有對D的邊緣。因此,等級化將會說D應該得到4的等級no。但是D已經具有分配的「較低等級」到它2.因此,任何時候你試圖級別數分配到一個節點,而這樣做已經有設置爲它一個較低的水平數DFS,你知道有向圖有一個週期..

approach2:
使用3種顏色。白色,灰色,黑色。只有白色節點纔會着色,當您沿DFS走向時,白色節點變爲灰色,當遞歸展開時(處理所有子節點),將灰色節點變爲黑色。如果不是所有的孩子都處理完畢,並且你打了一個灰色節點,那就是一個循環。 例如:全部白色以直接上圖開始。顏色A,B,D,F,G顏色爲白色灰色。 G是葉子,所以所有的孩子都把它染成灰色變成黑色。遞歸到F(所有處理過的孩子)將它染成黑色。現在你到達D,D有未加工的孩子,所以顏色E灰色,G已經着黑色,所以不要進一步下去。 E也有邊緣到D,所以在仍然處理D(D仍然是灰色)的時候,你會發現一個邊緣回到D(一個灰色節點),就會檢測到一個週期。

0

對給定圖形的拓撲排序測試將引導您找到解決方案。如果topsort的算法,即邊緣總是以一種方式定向失敗,那麼這意味着圖形包含循環。

2

使用DFS搜索如有路徑循環

class Node<T> { T value; List<Node<T>> adjacent; } 

class Graph<T>{ 

    List<Node<T>> nodes; 

    public boolean isCyclicRec() 
    { 

     for (Node<T> node : nodes) 
     { 
      Set<Node<T>> initPath = new HashSet<>(); 
      if (isCyclicRec(node, initPath)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

    private boolean isCyclicRec(Node<T> currNode, Set<Node<T>> path) 
    { 
     if (path.contains(currNode)) 
     { 
     return true; 
     } 
     else 
     { 
     path.add(currNode); 
     for (Node<T> node : currNode.adjacent) 
     { 
      if (isCyclicRec(node, path)) 
      { 
       return true; 
      } 
      else 
      { 
       path.remove(node); 
      } 
     } 
     } 
     return false; 
    } 
+0

您尚未定義函數isCyclic。 – 2015-12-04 16:47:26

+0

此代碼在此輸入上失敗:4 - > 1-> 2-> 3。它會失敗,如果你開始從節點1探索。 – 2016-07-03 20:34:05

+1

找到如何解決:設置> initPath = new HashSet <>();應該在裏面for循環。 – 2016-07-03 20:44:26