The Only Graph Traversal Algorithm

Question. How to visit every vertex exactly once in a graph?

Let T be the generic type name. We will make up an imaginary data structure called a Bag<T>. It has 3 methods:

  1. put(element: T) puts an element in the bag.
  2. popFirst() -> T returns whatever is the "first" thing in the bag and removes it.
  3. isEmpty() -> bool returns whether the bag is empty or not.

Then the pseudocode for whatever first search is:

function WhateverFirstSearch(G: Graph, start: Vertex):
	for each vertex v in G:
		mark v as NEW

	bag = Bag<Vertex>()
	bag.put(start)

	while bag is not empty:
		u = bag.popFirst()
		if u is NEW:
			process(u) 
			mark u as SEEN
			for each v adjacent to u:
				bag.put(v)

Here process(u) is just a blackbox subroutine. We can do anything inside process(u) as long as we don’t change the vertex status.

Important Variants

By changing the bag's behavior of popFirst() and put(element), we get the familiar search algorithms:

Stack

Depth First Search. DFS is usually implemented with recursion allowing cycle detection.

  • put(element) appends to the end
  • popFirst() pops from the end
Queue

Breadth First Search

  • put(element) appends to the end
  • popFirst() pops from the front
Priority Queue

Best First Search

  • put(element) appends with a priority value in O(\log n) time
  • popFirst() pops the element with highest priority in O(\log n) time.

Python

The WhateverFirstSearch_Connected function implements this. Github

To handle disconnected graphs we need to make the following modifications.

Whatever First Search–All

For each vertex in G, if we’ve never visited this vertex before, visit everything that we can reach from this vertex.

We will make a small wrapper.

// main routine
function WhateverFirstSearch(G: Graph):
	for each vertex v in G:
		mark v as NEW
	for each vertex v in G:
		if v is NEW:
			WhateverFirstVisit(G, v)
			
function WhateverFirstVisit(G: Graph, start: Vertex):
	bag = Bag<Vertex>()
	bag.put(start)

	while bag is not empty:
		u = bag.popFirst()
		if u is not SEEN:
			process(u)
			mark u as SEEN
			for each v adjacent to u:
				bag.put(v)

Changing the bag's behavior on popFirst() will result in the same variants, but now they can handle disconnected graphs.

Python

The WhateverFirstSearch_All function implements this. Github