Path compression (source code)

= Path compression

<Path compression> changes parent pointers during a <disjoint-set find operation> so that future queries traverse fewer <edges>. Full <path compression> first follows the entire parent route to its <root of a tree>, then makes every member on that route point directly to that same <root of a tree>. No member changes its <block of a set partition> or its <disjoint-set representative>. Pointers outside the traversed route stay as they were. The following iterative Python implements full <path compression> and <union by rank>; `parent` and `rank` are initially indexed <arrays> with `parent[x] = x` and `rank[x] = 0` for every valid member.

``
def find(x):
    root = x
    while parent[root] != root:
        root = parent[root]
    while parent[x] != x:
        following = parent[x]
        parent[x] = root
        x = following
    return root

def unite(x, y):
    a, b = find(x), find(y)
    if a == b:
        return False
    if rank[a] < rank[b]:
        a, b = b, a
    parent[b] = a
    if rank[a] == rank[b]:
        rank[a] += 1
    return True
``

Starting from the displayed <disjoint-set forest>, `find(3)` traverses $3\to4\to2$, returns $2$ and changes only $\mathrm{parent}[3]$ from $4$ to $2$. The route $5\to6\to2$ still has two <edges>. Then `find(5)` changes only $\mathrm{parent}[5]$ from $6$ to $2$. The final parent <array> is $(2,2,2,2,2,2,7)$; every stored rank retains its displayed value. The <rooted tree> at $2$ now has height one although its root's rank is two. Root $7$ still represents a separate <singleton set>.

\Image[/disjoint-set-union-path-compression-rank.png]
{title=Full <path compression> shortens two parent routes while <union by rank> metadata stays unchanged}
{description=Arrows point towards the <parent in a rooted tree>; self-pointers at roots are omitted. The same <partition of a set> appears before and after `find(3)` followed by `find(5)`. Labels $r$ record stored ranks, including historical ranks at nonroots.}

The two-pass <algorithm> first discovers the answer and then reuses it. During the second pass, saving `following` before overwriting the pointer preserves the remaining route. Every replacement pointer targets the original <root of a tree>, proving that the <partition of a set> is unchanged.

Full <path compression> is one specific rule. The authored `UF.java` implementation instead uses path halving, redirecting a visited member to its parent's parent while advancing along the route. Its <union by rank> rule agrees with the one above.<Algorithms, 4th edition by Robert Sedgewick and others/UF.java>[Algorithms, 4th edition by Robert Sedgewick and others; UF.java, find and union methods: halving assignment versus the full-compression algorithm here; lower-rank linking and equal-rank increment]{ref}