Algorithm Search⌘K

Proofs: Generic component-growing algorithm

These are the human proofs of Generic component-growing algorithm, at full length.

Component growing labels each component and builds a spanning forest full

This proof shows: correctness.

Let G=(V,E)G = (V, E) be an undirected graph with the lists Adj[v]\mathrm{Adj}[v], where an edge {u,v}\{u, v\} with u≠vu \neq v is in both lists. Parallel edges and loops are allowed. Write C(s)C(s) for the set of vertices joined to ss by a path, and Lk={v:comp[v]=k}L_k = \{ v : \mathrm{comp}[v] = k \}.

Lemma 1. Consider a call GROW(G,s,k)(G, s, k) that starts with comp[s]=nil\mathrm{comp}[s] = \mathrm{nil} and with no vertex labelled kk. After each step of the loop of line L3 these invariants hold:

(I1) Every v∈Lkv \in L_k is in C(s)C(s), and following parent pointers from vv reaches ss through vertices of LkL_k.

(I2) For each u∈Lku \in L_k, the entries Adj[u][0…next[u]−1]\mathrm{Adj}[u][0 \ldots \mathrm{next}[u] - 1] all lead to vertices of LkL_k.

(I3) Each u∈Lk∖Fu \in L_k \setminus F has next[u]=∣Adj[u]∣\mathrm{next}[u] = |\mathrm{Adj}[u]|, and F⊆LkF \subseteq L_k.

Proof. After lines L1 and L2, Lk=F={s}L_k = F = \{s\} and next[s]=0\mathrm{next}[s] = 0, so all three hold. Take a step with the vertex u∈Fu \in F of line L4.

If line L5 removes uu, then next[u]=∣Adj[u]∣\mathrm{next}[u] = |\mathrm{Adj}[u]|, so (I3) holds for uu, and nothing else changes.

Otherwise line L6 reads v=Adj[u][next[u]]v = \mathrm{Adj}[u][\mathrm{next}[u]] and moves the pointer by one. If comp[v]=k\mathrm{comp}[v] = k, the new entry leads into LkL_k and (I2) holds. The label of vv cannot be a smaller value k′<kk' < k: by Lemma 2 applied to the earlier call, Lk′L_{k'} is a full component, u∉Lk′u \notin L_{k'}, and vv is a neighbour of uu, so v∉Lk′v \notin L_{k'}. If comp[v]=nil\mathrm{comp}[v] = \mathrm{nil}, line L8 puts vv into LkL_k and into FF with next[v]=0\mathrm{next}[v] = 0 and parent[v]=u\mathrm{parent}[v] = u. Then v∈C(s)v \in C(s) because u∈C(s)u \in C(s) and {u,v}\{u, v\} is an edge, and the parent chain of vv is vv followed by the chain of uu, so (I1) holds. The entry just read leads to v∈Lkv \in L_k, so (I2) holds, and v∈Fv \in F, so (I3) holds. □\square

Lemma 2. The call stops, and then Lk=C(s)L_k = C(s).

Proof. Each step either moves a pointer forward or removes a vertex from FF. A pointer moves at most ∣Adj[u]∣|\mathrm{Adj}[u]| times, a vertex enters FF only once (when it gets its label), and so the loop runs at most ∑u∣Adj[u]∣+∣V∣\sum_u |\mathrm{Adj}[u]| + |V| times.

When F=∅F = \emptyset, (I3) gives next[u]=∣Adj[u]∣\mathrm{next}[u] = |\mathrm{Adj}[u]| for each u∈Lku \in L_k, and (I2) then says that every neighbour of every vertex of LkL_k is in LkL_k. Let w∈C(s)w \in C(s) and let s=x0,x1,…,xr=ws = x_0, x_1, \ldots, x_r = w be a path. Since x0∈Lkx_0 \in L_k and LkL_k is closed under neighbours, induction on ii gives xi∈Lkx_i \in L_k, so w∈Lkw \in L_k. Thus C(s)⊆LkC(s) \subseteq L_k, and (I1) gives Lk⊆C(s)L_k \subseteq C(s). □\square

Theorem. COMPONENTS(G)(G) returns labels with comp[u]=comp[v]\mathrm{comp}[u] = \mathrm{comp}[v] if and only if uu and vv lie in the same component, kk equal to the number of components, and parent pointers that form a spanning forest of GG with one tree for each component.

Proof. By induction over the loop of line L10, before the iteration for ss the labelled vertices are the union of the components of the vertices 0,…,s−10, \ldots, s-1, and each value k′<kk' < k labels exactly one component. If comp[s]≠nil\mathrm{comp}[s] \neq \mathrm{nil}, ss lies in one of these components and nothing changes. Otherwise ss lies in none of them, so no vertex of C(s)C(s) has a label, and by Lemma 2 the call labels exactly C(s)C(s) with the new value kk. So at the end each component has its own label and kk is their number.

Each vertex v≠sv \neq s of C(s)C(s) gets exactly one parent, in line L8, and its parent got its label earlier. So the parent edges in C(s)C(s) have no cycle, they number ∣C(s)∣−1|C(s)| - 1, and by (I1) they join every vertex to ss. They form a spanning tree of C(s)C(s), and over all components a spanning forest. ■\blacksquare

The proof does not use the rule of line L4, so it holds for every rule, which is the point of the generic algorithm.

Back to Generic component-growing algorithm