Files
ar_basalt/include/basalt/utils/union_find.h
2022-04-05 11:42:28 +03:00

95 lines
3.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Adapted from OpenMVG
// Copyright (c) 2016 Pierre MOULON
// 2018 Nikolaus DEMMEL
// This file was originally part of OpenMVG, an Open Multiple View Geometry C++
// library.
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#pragma once
#include <cstdint>
#include <limits>
#include <numeric>
#include <vector>
// Union-Find/Disjoint-Set data structure
//--
// A disjoint-set data structure also called a unionfind data structure
// or mergefind set, is a data structure that keeps track of a set of elements
// partitioned into a number of disjoint (non-overlapping) subsets.
// It supports two operations:
// - Find: Determine which subset a particular element is in.
// - It returns an item from this set that serves as its "representative";
// - Union: Join two subsets into a single subset.
// Sometime a Connected method is implemented:
// - Connected:
// - By comparing the result of two Find operations, one can determine whether
// two elements are in the same subset.
//--
struct UnionFind {
using ValueType = uint32_t;
// Special Value for invalid parent index
static ValueType InvalidIndex() {
return std::numeric_limits<ValueType>::max();
}
// Represent the DS/UF forest thanks to two array:
// A parent 'pointer tree' where each node holds a reference to its parent
// node
std::vector<ValueType> m_cc_parent;
// A rank array used for union by rank
std::vector<ValueType> m_cc_rank;
// A 'size array' to know the size of each connected component
std::vector<ValueType> m_cc_size;
// Init the UF structure with num_cc nodes
void InitSets(const ValueType num_cc) {
// all set size are 1 (independent nodes)
m_cc_size.resize(num_cc, 1);
// Parents id have their own CC id {0,n}
m_cc_parent.resize(num_cc);
std::iota(m_cc_parent.begin(), m_cc_parent.end(), 0);
// Rank array (0)
m_cc_rank.resize(num_cc, 0);
}
// Return the number of nodes that have been initialized in the UF tree
std::size_t GetNumNodes() const { return m_cc_size.size(); }
// Return the representative set id of I nth component
ValueType Find(ValueType i) {
// Recursively set all branch as children of root (Path compression)
if (m_cc_parent[i] != i && m_cc_parent[i] != InvalidIndex())
m_cc_parent[i] = Find(m_cc_parent[i]);
return m_cc_parent[i];
}
// Replace sets containing I and J with their union
void Union(ValueType i, ValueType j) {
i = Find(i);
j = Find(j);
if (i == j) { // Already in the same set. Nothing to do
return;
}
// x and y are not already in same set. Merge them.
// Perform an union by rank:
// - always attach the smaller tree to the root of the larger tree
if (m_cc_rank[i] < m_cc_rank[j]) {
m_cc_parent[i] = j;
m_cc_size[j] += m_cc_size[i];
} else {
m_cc_parent[j] = i;
m_cc_size[i] += m_cc_size[j];
if (m_cc_rank[i] == m_cc_rank[j]) ++m_cc_rank[i];
}
}
};