95 lines
3.1 KiB
C++
95 lines
3.1 KiB
C++
// 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 union–find data structure
|
||
// or merge–find 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];
|
||
}
|
||
}
|
||
};
|