Middle · Algorithms

Union-find: connectivity without repeated graph searches

How do you answer many connectivity queries while undirected edges are added?

Try explaining this aloud before opening the answer. State your assumptions and trace a boundary case.

ALGORITHM LAB · STEP THROUGH THE INVARIANT

n=5, edges=[(0, 1), (1, 2), (3, 4)]

STEP 1 / 4

Separate components

parent
00
11
22
33
44
size
10
11
12
13
14
components
50

Each vertex initially owns its own root.

Computed traces for these inputs. Indexes identify cell positions; active cells are labeled as well as highlighted. Compare a boundary case using the scenario selector. No code is sent to a server.

EXAMPLE · FRAGMENT UNLESS A COMPLETE PROGRAM IS SHOWN

go
type DisjointSet struct {
	parent, size []int
	Components   int
}

// Caller supplies a nonnegative n and valid IDs to Find and Union.
func NewDisjointSet(n int) *DisjointSet {
	d := &DisjointSet{parent: make([]int, n), size: make([]int, n), Components: n}
	for i := range d.parent {
		d.parent[i] = i
		d.size[i] = 1
	}
	return d
}
func (d *DisjointSet) Find(x int) int {
	for x != d.parent[x] {
		d.parent[x] = d.parent[d.parent[x]]
		x = d.parent[x]
	}
	return x
}
func (d *DisjointSet) Union(a, b int) bool {
	a, b = d.Find(a), d.Find(b)
	if a == b {
		return false
	}
	if d.size[a] < d.size[b] {
		a, b = b, a
	}
	d.parent[b] = a
	d.size[a] += d.size[b]
	d.Components--
	return true
}
Reveal a strong answer
  1. A disjoint-set structure represents each component by a root. Find follows parent links; Union joins roots only when they differ. Joining by size keeps trees shallow, while path compression shortens future searches.

  2. An attempted union of vertices already in one component must not decrement the component count. This supports dynamic connectivity as edges are added and cycle checks for undirected graphs; it does not produce shortest paths.

  3. Ordinary union-find does not support arbitrary edge deletion. It mutates internal state even during compressed Find, so shared concurrent use needs synchronization. Validate vertex IDs and define behavior for an empty structure.

Common trap

Comparing immediate parents rather than roots, or decrementing the component count for a redundant union.

Complexity & use

Amortized O(α(V)) per operation with union by size and path compression, O(V) storage; a single operation is not promised constant worst-case time.

Try it

Start with five vertices and join (0,1), (1,2), (3,4), then join (0,2) again.

Worked solution

Five components become four, three and two. The final union finds both endpoints already rooted in the same component, so the count remains two. Vertices 0 and 2 are connected; 0 and 4 are not.

Change the constraint

Why does finding a root not provide the route between the original graph vertices?

How did you do?

Self-assessment, not a compiler pass or interview score. Explain the reasoning unaided before marking understood.

Not marked. Progress stays on this browser, separate from course completion.

Primary references

Checked 2026-10-27. Use documentation for your pinned runtime, driver and tool version.