Proofs: Hierholzer's algorithm
These are the human proofs of Hierholzer's algorithm, at full length.
Hierholzer's algorithm returns an Eulerian trail exactly when one exists full
This proof shows: correctness, termination.
Let be a finite graph with edges, directed or undirected, with parallel edges and self-loops allowed. Write for the set of unused edges at a given moment. For a vertex , the excess of in an edge set is if is undirected, and if is directed; a loop adds 2 to , and 1 to both and . Call balanced if every vertex has excess 0. For a trail from to with edge set : if , is balanced; if , the excess is 1 at and at (undirected), or at and at (directed), and 0 elsewhere. This holds because each inner visit of a vertex uses one edge in and one edge out.
Lemma 1 (stuck walks). Let be a vertex and let . Extend a trail from by unused edges of , one at a time, until the last vertex has no unused edge of left (leaving , if directed). If is balanced, then . If has nonzero excess exactly at and one other vertex , with excess at if directed, then .
Proof. Suppose , and let be the edges of the trail. The trail ends at , so the excess of in is 1 (undirected) or (directed). All edges of at (leaving , if directed) are in . Undirected: then is odd. Directed: and , so the excess of in is at most . In both cases has nonzero excess in and . If is balanced, this is impossible, so . Otherwise . The walk stops, because each step uses a new edge.
Setup. Line L1 returns "no" exactly when the degree condition fails; that answer is correct, since by the trail fact above the edge set of an Eulerian trail has the excess pattern of a trail. From here on the condition holds, so is balanced, or has nonzero excess exactly at and one other vertex (with at if directed), by the choice of at line L2. In the balanced case put .
Write the stack as from bottom to top, with and , and write as in the order of appending.
Invariant. At each test of line L5:
- are distinct and joins to ; so the stack is a trail from to .
- For , the edge joins to ; so is a trail ending at .
- If , then , and no vertex has an unused edge at it (leaving it, if directed).
- If and the stack is not empty, let be the index of the top entry right after the last pop. Then joins to , every entry above was pushed after the last pop, the set of edges that were unused right after the last pop is balanced, and the used edges are exactly , each once.
- If , the used edges are exactly .
Initialization. The stack is and is empty. Parts 1 and 5 hold, and parts 2 to 4 say nothing.
Push. Lines L8 to L10 use an unused edge from the top to and push . Parts 1 and 5 hold, parts 2 and 3 are unchanged (an edge became used, which keeps part 3), and part 4 holds with the same and , with added to the used edges.
First pop. While , the algorithm has only pushed, building a walk as in Lemma 1 from in . The first pop happens when the top vertex has no unused edge, so by Lemma 1. The pop appends , and has no unused edge, so parts 2 and 3 hold. After the pop the top is , so and joins to . The used edges form the stack trail from to , which has the same excess pattern as , so minus these edges is balanced. Part 4 holds. If at the first pop, has no edge (leaving it, if directed), so by the choice of , and the stack is now empty.
Later pops. Let , and let line L11 run with top , which has no unused edge. By part 4, the entries above were pushed after the last pop, from the unused edges of the balanced set , starting at , and the walk is now stuck at . By Lemma 1 with and , we get (if this is trivial). So the edges form a closed trail and are balanced, and the unused edges are balanced. The pop appends . Part 2 for the pair : it joins to . Part 3: has no unused edge, and is unchanged. Part 4 after the pop: the new top is , the new is , joins to , nothing is above the top, the new is , which is balanced, and the used edges did not change. Parts 1 and 5 hold for the shorter stack.
Termination. Each iteration pushes a new edge, at most times in all, or pops one of at most pushed pairs. So the loop ends after at most iterations, with an empty stack.
Output. The last pop removes , so and . By part 2, reversed, , is a trail from to , and by part 4 just before the last pop, its edges are exactly the used edges, each once. So is the number of used edges plus 1.
Theorem. HIERHOLZER terminates. It returns an Eulerian trail of if one exists, and that trail is closed if has an Eulerian circuit. Otherwise it reports that none exists.
Proof. Termination was shown. If line L1 answers no, no Eulerian trail exists. Otherwise, if , all edges are used, and line L13 returns a trail from to that uses every edge once. If an Eulerian circuit exists, is balanced, so and the trail is closed.
If , some edge is unused. Then , so line L2 chose with at least one edge, and that edge is used, because the first push takes an edge at when one exists (one leaving when directed: if is balanced and has an edge, has an edge leaving it). By part 3, no vertex of the trail touches an unused edge. Every used edge has both ends on . So the edges of split into the used edges and the unused edges with no common vertex, both sets nonempty, so the edges do not lie in one connected component (weakly connected, if directed). By Euler's theorem, no Eulerian trail exists, and line L12 reports that correctly.