#ifndef DISJOINT_SET_H #define DISJOINT_SET_H /* disjoint_set.h */ #include "core/containers/rb_map.h" #include "core/containers/vector.h" /** @author Marios Staikopoulos */ /* This DisjointSet class uses Find with path compression and Union by rank */ template , class AL = DefaultAllocator> class DisjointSet { struct Element { T object; Element *parent = nullptr; int rank = 0; }; typedef RBMap MapT; MapT elements; Element *get_parent(Element *element); _FORCE_INLINE_ Element *insert_or_get(T object); public: ~DisjointSet(); _FORCE_INLINE_ void insert(T object) { (void)insert_or_get(object); } void create_union(T a, T b); void get_representatives(Vector &out_roots); void get_members(Vector &out_members, T representative); }; /* FUNCTIONS */ template DisjointSet::~DisjointSet() { for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { memdelete_allocator(itr->value()); } } template typename DisjointSet::Element *DisjointSet::get_parent(Element *element) { if (element->parent != element) { element->parent = get_parent(element->parent); } return element->parent; } template typename DisjointSet::Element *DisjointSet::insert_or_get(T object) { typename MapT::Element *itr = elements.find(object); if (itr != nullptr) { return itr->value(); } Element *new_element = memnew_allocator(Element, AL); new_element->object = object; new_element->parent = new_element; elements.insert(object, new_element); return new_element; } template void DisjointSet::create_union(T a, T b) { Element *x = insert_or_get(a); Element *y = insert_or_get(b); Element *x_root = get_parent(x); Element *y_root = get_parent(y); // Already in the same set if (x_root == y_root) { return; } // Not in the same set, merge if (x_root->rank < y_root->rank) { SWAP(x_root, y_root); } // Merge y_root into x_root y_root->parent = x_root; if (x_root->rank == y_root->rank) { ++x_root->rank; } } template void DisjointSet::get_representatives(Vector &out_representatives) { for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { Element *element = itr->value(); if (element->parent == element) { out_representatives.push_back(element->object); } } } template void DisjointSet::get_members(Vector &out_members, T representative) { typename MapT::Element *rep_itr = elements.find(representative); ERR_FAIL_COND(rep_itr == nullptr); Element *rep_element = rep_itr->value(); ERR_FAIL_COND(rep_element->parent != rep_element); for (typename MapT::Element *itr = elements.front(); itr != nullptr; itr = itr->next()) { Element *parent = get_parent(itr->value()); if (parent == rep_element) { out_members.push_back(itr->key()); } } } #endif