Rilasciato · in miglioramento
Guida a Union-Find · 1/6
Per ora questo capitolo è disponibile solo in inglese.
Union-find is a data structure that keeps a collection of elements split into non-overlapping groups. It is also called the disjoint-set data structure, or DSU (disjoint set union). This chapter covers the problem it solves, its two core operations, and the vocabulary you will meet when studying it.
Two sets are disjoint when they share no element. Splitting all elements into disjoint sets so that every element belongs to exactly one of them is called a partition. For example, the elements 0 to 5 can be partitioned into {0, 1, 2}, {3, 4} and {5}.
Union-find stores such a partition and is built to answer two questions quickly:
To check whether two elements are in the same set, compare find(a) == find(b). The key trick is that sets have no separate names; one member of each set acts as its representative.
Imagine that everyone at a school starts out alone. Each time news arrives such as "Alex and Beth became friends" or "Beth and Chris became friends", you merge the groups the two people belong to. Alex and Chris end up in the same group even though they have never met. Relationships that chain transitively, connections that only ever get added, and a single question, "same group?", are exactly the setting where union-find shines.
The simplest implementation writes a group label next to every element. find is instant, but every union has to scan the whole array.
# Naive approach (quick-find): one union costs O(n)
label = list(range(6))
def find(x):
return label[x]
def union(a, b):
la, lb = label[a], label[b]
for i in range(len(label)):
if label[i] == lb:
label[i] = la
union(0, 1)
union(1, 2)
print(find(2) == find(0)) # TrueUnion-find represents each set as a tree and the whole partition as a forest of trees. Every element remembers only its parent; an element that is its own parent is a root, which is the representative of its set. find walks up the parent links to the root, and union simply hangs one root under the other.
parent = list(range(6)) # initially every element is its own root
def find(x):
while parent[x] != x:
x = parent[x]
return x
def union(a, b):
ra, rb = find(a), find(b)
if ra != rb:
parent[rb] = ra # always link roots, never arbitrary nodes
union(0, 1); union(1, 2); union(3, 4)
print([find(x) for x in range(6)]) # [0, 0, 0, 3, 3, 5]After running the code above, the parent array is [0, 0, 0, 3, 3, 5]. Three slots point to themselves, 0, 3 and 5, so there are three sets. The number of roots is always the number of sets, and every successful merge removes exactly one root.
This basic version slows down when a tree degenerates into a long chain. In practice it is paired with two optimizations, path compression and union by rank or size, which the next chapter walks through.
Union-find only tells you whether two elements are connected, not how. If you need the actual path or a shortest distance, use a graph search such as BFS or DFS. And if the graph is static and you only need the answer once, a single DFS pass over the components may be simpler.
If you need to split sets apart again or delete elements, plain union-find is not enough. Remember the constraint: sets can only be merged.
| Term | Meaning |
|---|---|
| Representative | The element that stands for a set, the root of its tree |
| parent array | Stores the parent of every element |
| Rank | An upper bound on a tree's height |
| Size | The number of elements in a set |
| Path compression | Re-attaching visited nodes closer to the root during find |
| Amortized cost | The average cost per operation over a whole sequence |
# Asking "same set?" takes just two finds
def connected(a, b):
return find(a) == find(b)
print(connected(0, 2), connected(2, 3)) # True FalseUnion-find stores a partition into disjoint sets in a single parent array, uses find to locate a set's representative and union to merge two sets. It is ideal when relations are transitive and connections only grow, and with two small optimizations each operation runs in nearly constant time.
0 commenti
Accedi · Accedi per lasciare un commento.
Scrivi tu il primo commento.