In a directed graph with a fixed entry , vertex dominates if every path from to passes through . Each has a unique immediate dominator — its closest strict dominator — and these form a tree.

Basic facts

  • dominates everything reachable from it.
  • Dominance is a partial order; the dominators of form a chain from to .
  • is the parent of in the dominator tree.
  • The set of vertices dominated by is exactly ‘s subtree in the dominator tree.
  • Unreachable vertices are simply excluded.

Algorithms

MethodTimeDifficulty
Iterative dataflow (Cooper-Harvey-Kennedy) worst, near-linear in practiceeasy — ~30 lines
Lengauer-Tarjan simplehard
Lengauer-Tarjan sophisticatedvery hard
Alstrup et al.theoretical

The easy algorithm

Process vertices in reverse postorder, repeatedly intersecting dominator sets until a fixed point:

vector<int> idom, order, rpoNum;      // reverse postorder numbering
 
int intersect(int a, int b) {          // "closest common dominator"
    while (a != b) {
        while (rpoNum[a] > rpoNum[b]) a = idom[a];
        while (rpoNum[b] > rpoNum[a]) b = idom[b];
    }
    return a;
}
 
void computeIdom(int root) {
    idom.assign(n, -1);
    idom[root] = root;
    bool changed = true;
    while (changed) {
        changed = false;
        for (int u : order) {                     // reverse postorder, skip root
            if (u == root) continue;
            int newIdom = -1;
            for (int p : rpred[u]) {
                if (idom[p] == -1) continue;
                newIdom = (newIdom == -1) ? p : intersect(p, newIdom);
            }
            if (newIdom != -1 && idom[u] != newIdom) { idom[u] = newIdom; changed = true; }
        }
    }
}

This converges in very few iterations on real graphs and is what to write unless is enormous.

Special cases that are much easier

GraphDominator tree
DAGprocess in topological order; of all predecessors in the partially built tree
Treethe tree itself
Undirected connectedevery vertex’s idom is its parent in any BFS/DFS tree only if… (in general, use the block-cut tree instead)
Reducible flow graph (structured code)the iterative algorithm converges in passes where is the loop nesting depth

The DAG case is worth remembering: with a topological order and an incremental LCA structure, you get the dominator tree in with code you probably already have.

What it answers

QuestionOn the dominator tree
Which vertices become unreachable if fails?’s subtree
How many vertices depend on ?subtree size
Is required to reach ?is an ancestor of
Critical single points of failurevertices with large subtrees
Vertices reachable only through subtree minus

Where it comes from

Dominators were invented for compilers. In SSA (static single assignment) construction, a -function for variable is needed exactly at the dominance frontier of ‘s definitions. Loop detection, code motion, and control dependence all use the dominator tree. Every optimising compiler computes one.

Post-dominators

Run the same algorithm on the reversed graph from the exit vertex. post-dominates if every path from to the exit passes through . The combination of dominators and post-dominators gives control dependence, which is what tells a compiler which statements are conditionally executed.

See also: Lengauer-Tarjan · LCA · SCC