// Copyright (c) 1997-2000 // Utrecht University (The Netherlands), // ETH Zurich (Switzerland), // INRIA Sophia-Antipolis (France), // Max-Planck-Institute Saarbruecken (Germany), // and Tel-Aviv University (Israel). All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/Union_find/include/CGAL/Union_find.h $ // $Id: Union_find.h fcd4e57 2020-05-22T11:29:03+02:00 Marc Glisse // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Michael Seel , // Lutz Kettner #ifndef CGAL_UNION_FIND_H #define CGAL_UNION_FIND_H #include #include #include namespace CGAL { namespace internal { template class UF_forward_iterator { PTR_ m_p; public: // should be private and Union_find<...> a friend. PTR_ ptr() const { return m_p; } typedef UF_forward_iterator Self; typedef V_ value_type; typedef R_ reference; typedef P_ pointer; typedef std::forward_iterator_tag iterator_category; UF_forward_iterator() : m_p(0) {} UF_forward_iterator(PTR_ p) : m_p(p) {} // Allows construction of const_iterator from iterator template UF_forward_iterator(const UF_forward_iterator& i) : m_p(i.ptr()) {} bool operator==( const Self& x) const { return m_p == x.m_p; } bool operator!=( const Self& x) const { return !(*this == x); } bool operator<(const Self& other) const{ return m_p(const Self& other) const{ return m_p>other.m_p; } bool operator<=(const Self& other) const{ return m_p<=other.m_p; } bool operator>=(const Self& other) const{ return m_p>=other.m_p; } reference operator*() const { return m_p->value; } pointer operator->() const { return &(m_p->value); } Self& operator++() { CGAL_assertion(m_p != 0); m_p = m_p->next; return *this; } Self operator++(int) { Self tmp = *this; ++*this; return tmp; } }; } // internal // Union-Find with path compression. // -------------------------------------------------------------------- // An instance of the data type Union_find is a partition of values of // type |T| into disjoint sets. The type |A| has to be a model of the // allocator concept as defined in the C++ standard. // Union_find is implemented with union by rank and path compression. // The running time for $m$ set operations on $n$ elements is // $O(n \alpha(m,n))$ where $\alpha(m,n)$ is the extremely slow // growing inverse of Ackermann's function. template class Union_find { struct Union_find_struct { typedef Union_find_struct* pointer; // friend class Union_find; mutable pointer up; pointer next; std::size_t size; T value; Union_find_struct( pointer n, const T& x) : up(0), next(n), size(1), value(x) {} }; public: typedef Union_find Self; typedef Union_find_struct* pointer; typedef const Union_find_struct* const_pointer; typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef internal::UF_forward_iterator< pointer, T, T&, T*> iterator; typedef iterator handle; typedef internal::UF_forward_iterator< const_pointer, T, const T&, const T*> const_iterator; typedef const_iterator const_handle; #ifdef _MSC_VER typedef CGAL_ALLOCATOR(Union_find_struct) allocator; #else typedef typename std::allocator_traits::template rebind_alloc allocator; #endif private: pointer m_first; std::size_t sets; std::size_t values; allocator alloc; // Private decl. and no definition, thus no copy constructor // and no assignment for this class. Union_find(const Self&); Self& operator=(const Self&); pointer find( pointer p) const { CGAL_assertion(p != 0); pointer r = p; while (r->up) r = r->up; // now r is the root; while (p->up) { pointer u = p->up; p->up = r; // path compression: assign root r as new parent p = u; // this would need the 'mutable' for the up field } // if we would have a const_pointer, see the cast return r; // in the fct. below. We keep the mutable as reminder. } const_pointer find( const_pointer p ) const { return find( const_cast(p)); } bool is_valid(const_handle v) const { return v != const_handle(0); } public: Union_find() : m_first(0), sets(0), values(0) {} ~Union_find() { clear(); } allocator get_allocator() const { return alloc; } std::size_t number_of_sets() const { return sets; } // returns the number of disjoint sets std::size_t size() const { return values; } // returns the number of values std::size_t bytes() const { // returns the memory consumed return values * sizeof(Union_find_struct) + sizeof( Self); } std::size_t size( const_handle p) const { return find(p).ptr()->size; } // returns the size of the set containing $p$ void clear(); // reinitializes to an empty partition handle make_set(const T& x); // creates a new singleton set containing |x| and returns a handle to it handle push_back(const T& x) { return make_set(x); } // same as |make_set(x)| template void insert( Forward_iterator first, Forward_iterator beyond) { // insert the range of values referenced by |[first,beyond)|. // Precond: value type of |Forward_iterator| is |T|. while (first != beyond) push_back(*first++); } handle find( handle p) const { return find(p.ptr()); } const_handle find( const_handle p ) const { // returns a canonical handle of the set that contains |p|, // i.e., |P.same_set(p,q)| iff |P.find(p)| and |P.find(q)| return // the same handle. Precond: |p| is a handle in the union find structure. return find(p.ptr()); } void unify_sets(handle p, handle q); // unites the sets of partition containing $p$ and $q$. // Precond: $p$ and $q$ are in the partition. bool same_set( const_handle p, const_handle q) const { // returns true iff $p$ and $q$ belong to the same set. // Precond: $p$ and $q$ are in the partition. return find(p) == find(q); } iterator begin() { return iterator(m_first); } iterator end() { return iterator(0); } const_iterator begin() const { return const_iterator(m_first); } const_iterator end() const { return const_iterator(0); } }; template typename Union_find::handle Union_find::make_set(const T& x) { pointer tmp = m_first; m_first = alloc.allocate(1); std::allocator_traits::construct(alloc, m_first, tmp, x); ++sets; ++values; return handle( m_first); } template void Union_find::clear() { while (m_first) { pointer tmp = m_first->next; std::allocator_traits::destroy(alloc, m_first); alloc.deallocate(m_first,1); m_first = tmp; } sets = 0; values = 0; } template void Union_find::unify_sets( handle p, handle q) { CGAL_assertion( is_valid(p) && is_valid(q)); pointer pit = find( p.ptr()); pointer qit = find( q.ptr()); if (pit == qit) return; std::size_t sp = pit->size; std::size_t sq = qit->size; if (sp > sq) std::swap(pit,qit); // now sp <= sq pit->up = qit; // linking roots qit->size += pit->size; // updating size --sets; } } //namespace CGAL #endif // CGAL_UNION_FIND_H