You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

105 lines
3.2 KiB

  1. // Copyright 2005-2024 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the 'License');
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an 'AS IS' BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. //
  15. // See www.openfst.org for extensive documentation on this weighted
  16. // finite-state transducer library.
  17. //
  18. // Union-find algorithm for dense sets of non-negative integers, implemented
  19. // using disjoint tree forests with rank heuristics and path compression.
  20. #ifndef FST_UNION_FIND_H_
  21. #define FST_UNION_FIND_H_
  22. #include <vector>
  23. namespace fst {
  24. // Union-Find algorithm for dense sets of non-negative integers.
  25. template <class T>
  26. class UnionFind {
  27. public:
  28. // Creates a disjoint set forest for the range [0; max); 'fail' is a value
  29. // indicating that an element hasn't been initialized using MakeSet(...).
  30. // The upper bound of the range can be reset (increased) using MakeSet(...).
  31. UnionFind(T max, T fail) : parent_(max, fail), rank_(max), fail_(fail) {}
  32. // Finds the representative of the set 'item' belongs to, performing path
  33. // compression if necessary.
  34. T FindSet(T item) {
  35. if (item >= parent_.size() || item == fail_ || parent_[item] == fail_) {
  36. return fail_;
  37. }
  38. T root = item;
  39. while (root != parent_[root]) {
  40. root = parent_[root];
  41. }
  42. while (item != parent_[item]) {
  43. T parent = parent_[item];
  44. parent_[item] = root;
  45. item = parent;
  46. }
  47. return root;
  48. }
  49. // Creates the (destructive) union of the sets x and y belong to.
  50. void Union(T x, T y) { Link(FindSet(x), FindSet(y)); }
  51. // Initialization of an element: creates a singleton set containing 'item'.
  52. // The range [0; max) is reset if item >= max.
  53. T MakeSet(T item) {
  54. if (item >= parent_.size()) {
  55. // New value in parent_ should be initialized to fail_.
  56. const auto nitem = item > 0 ? 2 * item : 2;
  57. parent_.resize(nitem, fail_);
  58. rank_.resize(nitem);
  59. }
  60. parent_[item] = item;
  61. return item;
  62. }
  63. // Initialization of all elements starting from 0 to max - 1 to distinct sets.
  64. void MakeAllSet(T max) {
  65. parent_.resize(max);
  66. for (T item = 0; item < max; ++item) parent_[item] = item;
  67. }
  68. // For testing only.
  69. const T &Parent(const T &x) const { return parent_[x]; }
  70. private:
  71. // Links trees rooted in 'x' and 'y'.
  72. void Link(T x, T y) {
  73. if (x == y) return;
  74. if (rank_[x] > rank_[y]) {
  75. parent_[y] = x;
  76. } else {
  77. parent_[x] = y;
  78. if (rank_[x] == rank_[y]) {
  79. ++rank_[y];
  80. }
  81. }
  82. }
  83. UnionFind(const UnionFind &) = delete;
  84. UnionFind &operator=(const UnionFind &) = delete;
  85. std::vector<T> parent_; // Parent nodes.
  86. std::vector<int> rank_; // Rank of an element = min. depth in tree.
  87. T fail_; // Value indicating lookup failure.
  88. };
  89. } // namespace fst
  90. #endif // FST_UNION_FIND_H_