Graph Algorithms

How Cycle Detection Works

Cycle detection in a directed graph is a depth-first search that colours vertices white, grey and black. Reaching a grey vertex means you have walked back onto your own path, which is a cycle.

ABCDEFGH
Grey - still on the path
  1. A
Black - finished with

Nothing yet.

  • Not reached
  • Waiting
  • Current
  • Finished
1/20

Colour A grey: it is on the path we are exploring.

Counters

Visited
1/8
On the path
1
Cycle
none yet
Nodes on it
-

Settings

Graph
More options

Cycle detection

  1. 1colour[v] = white for all v
  2. 2
  3. 3visit(v):
  4. 4 colour[v] = grey
  5. 5 for each neighbour w:
  6. 6 if colour[w] == grey:
  7. 7 CYCLE - w is still on the path
  8. 8 if colour[w] == white: visit(w)
  9. 9 colour[v] = black

What each one answers

AlgorithmWhat it answersTimeNeeds
Breadth-firstFewest hops from the startO(V + E)A queue
Depth-firstReachability, one branch at a timeO(V + E)A stack
Cycle detectionDoes a cycle exist, and whereO(V + E)Node colours
Topological sortA valid order to do the work inO(V + E)No cycles
DijkstraCheapest path by edge weightO(E log V)Non-negative weights

Scroll the table sideways for the rest of the columns.

V is the number of nodes and E the number of edges. Switch to the graph with a cycle and the topological sort gets stuck: once a cycle exists there is no valid order.

Complexity

BestAverageWorstExtra memory
O(V + E)O(V + E)O(V + E)O(V)

One DFS. The colours are what make it work: a plain visited set cannot tell 'already finished' from 'currently on the stack', and only the second one is a cycle.

How cycle detection works

Colour every vertex white to begin with. A depth-first search turns a vertex grey when it enters and black when it finishes, so grey means exactly "on the path I am currently walking". An edge into a black vertex is harmless: that part of the graph is done. An edge into a grey vertex is a back edge: it points at a vertex still on the stack, which means there is a path from it to here and an edge from here to it. That is a cycle.

  1. Colour all vertices white.
  2. Start a DFS from any white vertex, colouring it grey on entry.
  3. Follow each edge: a white neighbour is recursed into, a grey neighbour means a cycle has been found.
  4. Colour the vertex black when all its edges are exhausted, and return.
  5. Repeat from any remaining white vertex, since the graph may be disconnected.

Implementation

Python
WHITE, GREY, BLACK = 0, 1, 2


def has_cycle(graph):
    colour = {node: WHITE for node in graph}

    def visit(node):
        colour[node] = GREY
        for neighbour in graph[node]:
            # Grey means "still on the current path" - that is a back edge.
            if colour[neighbour] == GREY:
                return True
            if colour[neighbour] == WHITE and visit(neighbour):
                return True
        colour[node] = BLACK
        return False

    return any(colour[node] == WHITE and visit(node) for node in graph)

More graph algorithms