24template <
class Idx = std::u
int32_t>
class UnionFind {
26 static_assert(std::is_unsigned_v<Idx>,
"UnionFind Idx must be an unsigned integer type");
33 explicit UnionFind(std::size_t n) : m_parent(n), m_rank(n, 0), m_size(n, 1), m_components(n) {
34 for (std::size_t i = 0; i < n; ++i) {
35 m_parent[i] =
static_cast<Idx
>(i);
50 assert(
static_cast<std::size_t
>(x) < m_parent.size() &&
"UnionFind::find index out of range");
52 while (m_parent[root] != root) {
53 root = m_parent[root];
56 while (m_parent[node] != root) {
57 const Idx next = m_parent[node];
58 m_parent[node] = root;
75 bool unite(Idx a, Idx b)
noexcept {
81 if (m_rank[ra] < m_rank[rb]) {
83 m_size[rb] += m_size[ra];
84 }
else if (m_rank[ra] > m_rank[rb]) {
86 m_size[ra] += m_size[rb];
89 m_size[ra] += m_size[rb];
121 [[nodiscard]] std::size_t
size() const noexcept {
return m_parent.size(); }
135 assert(
static_cast<std::size_t
>(root) < m_parent.size() &&
136 "UnionFind::componentSize index out of range");
141 std::vector<Idx> m_parent;
142 std::vector<std::uint8_t> m_rank;
143 std::vector<std::size_t> m_size;
144 std::size_t m_components;
164 static_assert(std::is_unsigned_v<Idx>,
"AtomicUnionFind Idx must be an unsigned integer type");
168 for (std::size_t i = 0; i < n; ++i) {
169 m_parent[i].store(
static_cast<Idx
>(i), std::memory_order_relaxed);
184 assert(
static_cast<std::size_t
>(x) < m_parent.size() &&
185 "AtomicUnionFind::find index out of range");
187 Idx parent = m_parent[x].load(std::memory_order_acquire);
191 const Idx grandparent = m_parent[parent].load(std::memory_order_acquire);
192 if (grandparent == parent) {
197 m_parent[x].compare_exchange_weak(parent, grandparent, std::memory_order_release,
198 std::memory_order_relaxed);
220 if (m_parent[rb].compare_exchange_strong(expected, ra, std::memory_order_acq_rel,
221 std::memory_order_acquire)) {
231 [[nodiscard]] std::size_t
size() const noexcept {
return m_parent.size(); }
234 std::vector<std::atomic<Idx>> m_parent;
AtomicUnionFind(std::size_t n)
Construct n singleton components numbered [0, n).
bool unite(Idx a, Idx b) noexcept
Merge the components containing a and b; larger root links under smaller.
Idx find(Idx x) noexcept
Root of the component containing x at some point during the call.
std::size_t size() const noexcept
Total number of elements under management (fixed at construction).
Idx find(Idx x) noexcept
Root of the component containing x, with path compression applied.
std::size_t size() const noexcept
Total number of elements under management (fixed at construction).
bool unite(Idx a, Idx b) noexcept
Merge the components containing a and b.
std::size_t componentSize(Idx root) const noexcept
Population of the component whose root is root.
UnionFind(std::size_t n)
Construct n singleton components numbered [0, n).
bool sameComponent(Idx a, Idx b) noexcept
Whether a and b share a component.
std::size_t countComponents() const noexcept
Current number of distinct components.