views:

4213

answers:

6

Given an undirected graph G=(V,E) with n vertices ( |V| = n ), how do you find if it contains a cycle in O(n) ?

+8  A: 

I think that depth first search solves it. If an unexplored edge leads to a node visited before, then the graph contains a cycle. This condition also makes it O(n), since you can explore maximum n edges without setting it to true or being left with no unexplored edges.

Rafał Dowgird
right! I remembered it was something simple...Thanks a lot :)
Eran Kampf
and if you go the breadth first search route, then an unexplored edge leading to a node "discovered" before, then the graph contains a cycle. BTW, IIRC the runtime of graph algorithms is usually described in terms of V and E.
ceretullis
Hmmm...this *could* devolve into an O(n^2) algorithm if you aren't careful, no? If you check for a node visited before by keeping all of the nodes in a linked list (new nodes to the end) then you'll have to scan your node list (the scan is O(n) in itself) on each check. Ergo - O(n^2).
Mark Brittingham
If you *mark* each node, though, it is definitely O(n).
Mark Brittingham
+3  A: 

The answer is, really, breadth first search (or depth first search, it doesn't really matter). The details lie in the analysis.

Now, how fast is the algorithm?

First, imagine the graph has no cycles. The number of edges is then O(V), the graph is a forest, goal reached.

Now, imagine the graph has cycles, and your searching algorithm will finish and report success in the first of them. The graph is undirected, and therefore, the when the algorithm inspects an edge, there are only two possibilities: Either it has visited the other end of the edge, or it has and then, this edge closes a circle. And once it sees the other vertex of the edge, that vertex is "inspected", so there are only O(V) of these operations. The second case will be reached only once throughout the run of the algorithm.

jpalecek
A: 

Actually, depth first (or indeed breadth first) search isn't quite enough. You need a sightly more complex algorithm.

For instance, suppose there is graph with nodes {a,b,c,d} and edges {(a,b),(b,c),(b,d),(d,c)} where an edge (x,y) is an edge from x to y. (looks something like this, with all edges directed downwards.)

    (a)
     |
     |
    (b)
    / \ 
  (d)  |
   |   |
    \ /
    (c)

Then doing depth first search may visit node a, then b then c then backtrack to c then visit d and finally visit c again and conclude there is a cycle when there isn't. A similar thing happens with breadth first.

What you need to do is keep track of which nodes your in the middle of visiting. In the example above, when the algorithm reaches (d) it has finished visiting (c) but not (a) or (b). So revisiting a finished node is fine, but visiting an unfinished node means you have a cycle. The usual way to do this is colour each node white(not yet visited), grey(visiting descendants) or black(finished visiting).

here is some pseudo code!

define visit(node n):
  if n.colour == grey: //if we're still visiting this node or its descendants
    throw exception("Cycle found")

  n.colour = grey //to indicate this node is being visited
  for node child in n.children():
    if child.colour == white: //if the child is unexplored
      visit(child)

  n.colour = black //to show we're done visiting this node
  return

then running visit(root_node) will throw an exception if and only if there is a cycle (initially all nodes should be white).

Sorry if you knew all this already, it may well be what you meant by depth first search anyway, but I hope it helps.

The question was for an undirected graph, your example is a cycle in a undirected graph.
David Waters
Hah, so it is...Guess I should read things more carefully!
A: 

I have a similar problem, but I want to have all cycles in undirected graph. Is there any polynomial algorithm?

Make this a separate question, not an answer.
A: 

I am interested in finding the total number of cycles and cycles length in an connected undirected graph. If I can use DFS or DFS can only find a single cycle. Any code will definitely help ......

Thanks!

Hassu

+1  A: 

I believe that the assumption that the graph is connected can be handful. thus, you can use the proof shown above, that the running time is O(|V|). if not, then |E|>|V|. reminder: the running time of DFS is O(|V|+|E|).

gor