| 1 | /**************************************************************************/ |
| 2 | /* disjoint_set.h */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #ifndef DISJOINT_SET_H |
| 32 | #define DISJOINT_SET_H |
| 33 | |
| 34 | #include "core/templates/rb_map.h" |
| 35 | #include "core/templates/vector.h" |
| 36 | |
| 37 | /* This DisjointSet class uses Find with path compression and Union by rank */ |
| 38 | template <typename T, class H = HashMapHasherDefault, class C = HashMapComparatorDefault<T>, class AL = DefaultAllocator> |
| 39 | class DisjointSet { |
| 40 | struct Element { |
| 41 | T object; |
| 42 | Element *parent = nullptr; |
| 43 | int rank = 0; |
| 44 | }; |
| 45 | |
| 46 | typedef HashMap<T, Element *, H, C> MapT; |
| 47 | |
| 48 | MapT elements; |
| 49 | |
| 50 | Element *get_parent(Element *element); |
| 51 | |
| 52 | _FORCE_INLINE_ Element *insert_or_get(T object); |
| 53 | |
| 54 | public: |
| 55 | ~DisjointSet(); |
| 56 | |
| 57 | _FORCE_INLINE_ void insert(T object) { (void)insert_or_get(object); } |
| 58 | |
| 59 | void create_union(T a, T b); |
| 60 | |
| 61 | void get_representatives(Vector<T> &out_roots); |
| 62 | |
| 63 | void get_members(Vector<T> &out_members, T representative); |
| 64 | }; |
| 65 | |
| 66 | /* FUNCTIONS */ |
| 67 | |
| 68 | template <typename T, class H, class C, class AL> |
| 69 | DisjointSet<T, H, C, AL>::~DisjointSet() { |
| 70 | for (KeyValue<T, Element *> &E : elements) { |
| 71 | memdelete_allocator<Element, AL>(E.value); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | template <typename T, class H, class C, class AL> |
| 76 | typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::get_parent(Element *element) { |
| 77 | if (element->parent != element) { |
| 78 | element->parent = get_parent(element->parent); |
| 79 | } |
| 80 | |
| 81 | return element->parent; |
| 82 | } |
| 83 | |
| 84 | template <typename T, class H, class C, class AL> |
| 85 | typename DisjointSet<T, H, C, AL>::Element *DisjointSet<T, H, C, AL>::insert_or_get(T object) { |
| 86 | typename MapT::Iterator itr = elements.find(object); |
| 87 | if (itr != nullptr) { |
| 88 | return itr->value; |
| 89 | } |
| 90 | |
| 91 | Element *new_element = memnew_allocator(Element, AL); |
| 92 | new_element->object = object; |
| 93 | new_element->parent = new_element; |
| 94 | elements.insert(object, new_element); |
| 95 | |
| 96 | return new_element; |
| 97 | } |
| 98 | |
| 99 | template <typename T, class H, class C, class AL> |
| 100 | void DisjointSet<T, H, C, AL>::create_union(T a, T b) { |
| 101 | Element *x = insert_or_get(a); |
| 102 | Element *y = insert_or_get(b); |
| 103 | |
| 104 | Element *x_root = get_parent(x); |
| 105 | Element *y_root = get_parent(y); |
| 106 | |
| 107 | // Already in the same set |
| 108 | if (x_root == y_root) { |
| 109 | return; |
| 110 | } |
| 111 | |
| 112 | // Not in the same set, merge |
| 113 | if (x_root->rank < y_root->rank) { |
| 114 | SWAP(x_root, y_root); |
| 115 | } |
| 116 | |
| 117 | // Merge y_root into x_root |
| 118 | y_root->parent = x_root; |
| 119 | if (x_root->rank == y_root->rank) { |
| 120 | ++x_root->rank; |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | template <typename T, class H, class C, class AL> |
| 125 | void DisjointSet<T, H, C, AL>::get_representatives(Vector<T> &out_representatives) { |
| 126 | for (KeyValue<T, Element *> &E : elements) { |
| 127 | Element *element = E.value; |
| 128 | if (element->parent == element) { |
| 129 | out_representatives.push_back(element->object); |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | template <typename T, class H, class C, class AL> |
| 135 | void DisjointSet<T, H, C, AL>::get_members(Vector<T> &out_members, T representative) { |
| 136 | typename MapT::Iterator rep_itr = elements.find(representative); |
| 137 | ERR_FAIL_NULL(rep_itr); |
| 138 | |
| 139 | Element *rep_element = rep_itr->value; |
| 140 | ERR_FAIL_COND(rep_element->parent != rep_element); |
| 141 | |
| 142 | for (KeyValue<T, Element *> &E : elements) { |
| 143 | Element *parent = get_parent(E.value); |
| 144 | if (parent == rep_element) { |
| 145 | out_members.push_back(E.key); |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | #endif // DISJOINT_SET_H |
| 151 | |