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.

188 lines
5.1 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. // Implementation of a heap as in STL, but allows tracking positions in heap
  19. // using a key. The key can be used to do an in-place update of values in the
  20. // heap.
  21. #ifndef FST_HEAP_H_
  22. #define FST_HEAP_H_
  23. #include <utility>
  24. #include <vector>
  25. #include <fst/compat.h>
  26. #include <fst/log.h>
  27. namespace fst {
  28. // A templated heap implementation that supports in-place update of values.
  29. //
  30. // The templated heap implementation is a little different from the STL
  31. // priority_queue and the *_heap operations in STL. This heap supports
  32. // indexing of values in the heap via an associated key.
  33. //
  34. // Each value is internally associated with a key which is returned to the
  35. // calling functions on heap insert. This key can be used to later update
  36. // the specific value in the heap.
  37. //
  38. // T: the element type of the hash. It can be POD, Data or a pointer to Data.
  39. // Compare: comparison functor for determining min-heapness.
  40. template <class T, class Compare>
  41. class Heap {
  42. public:
  43. using Value = T;
  44. static constexpr int kNoKey = -1;
  45. // Initializes with a specific comparator.
  46. explicit Heap(Compare comp = Compare()) : comp_(comp), size_(0) {}
  47. // Inserts a value into the heap.
  48. int Insert(const Value &value) {
  49. if (size_ < values_.size()) {
  50. values_[size_] = value;
  51. pos_[key_[size_]] = size_;
  52. } else {
  53. values_.push_back(value);
  54. pos_.push_back(size_);
  55. key_.push_back(size_);
  56. }
  57. ++size_;
  58. return Insert(value, size_ - 1);
  59. }
  60. // Updates a value at position given by the key. The pos_ array is first
  61. // indexed by the key. The position gives the position in the heap array.
  62. // Once we have the position we can then use the standard heap operations
  63. // to calculate the parent and child positions.
  64. void Update(int key, const Value &value) {
  65. const auto i = pos_[key];
  66. const bool is_better = comp_(value, values_[Parent(i)]);
  67. values_[i] = value;
  68. if (is_better) {
  69. Insert(value, i);
  70. } else {
  71. Heapify(i);
  72. }
  73. }
  74. // Returns the least value.
  75. Value Pop() {
  76. DCHECK(!Empty());
  77. Value top = values_.front();
  78. Swap(0, size_ - 1);
  79. size_--;
  80. Heapify(0);
  81. return top;
  82. }
  83. // Returns the least value w.r.t. the comparison function from the
  84. // heap.
  85. const Value &Top() const {
  86. DCHECK(!Empty());
  87. return values_.front();
  88. }
  89. // Returns the element for the given key.
  90. const Value &Get(int key) const {
  91. DCHECK_LT(key, pos_.size());
  92. return values_[pos_[key]];
  93. }
  94. // Checks if the heap is empty.
  95. bool Empty() const { return size_ == 0; }
  96. void Clear() { size_ = 0; }
  97. int Size() const { return size_; }
  98. void Reserve(int size) {
  99. values_.reserve(size);
  100. pos_.reserve(size);
  101. key_.reserve(size);
  102. }
  103. const Compare &GetCompare() const { return comp_; }
  104. private:
  105. // The following private routines are used in a supportive role
  106. // for managing the heap and keeping the heap properties.
  107. // Computes left child of parent.
  108. static int Left(int i) {
  109. return 2 * (i + 1) - 1; // 0 -> 1, 1 -> 3
  110. }
  111. // Computes right child of parent.
  112. static int Right(int i) {
  113. return 2 * (i + 1); // 0 -> 2, 1 -> 4
  114. }
  115. // Given a child computes parent.
  116. static int Parent(int i) {
  117. return (i - 1) / 2; // 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 1, 4 -> 1, ...
  118. }
  119. // Swaps a child and parent. Use to move element up/down tree. Note the use of
  120. // a little trick here. When we swap we need to swap:
  121. //
  122. // - the value
  123. // - the associated keys
  124. // - the position of the value in the heap
  125. void Swap(int j, int k) {
  126. const auto tkey = key_[j];
  127. pos_[key_[j] = key_[k]] = j;
  128. pos_[key_[k] = tkey] = k;
  129. using std::swap;
  130. swap(values_[j], values_[k]);
  131. }
  132. // Heapifies the subtree rooted at index i.
  133. void Heapify(int i) {
  134. const auto l = Left(i);
  135. const auto r = Right(i);
  136. auto largest = (l < size_ && comp_(values_[l], values_[i])) ? l : i;
  137. if (r < size_ && comp_(values_[r], values_[largest])) largest = r;
  138. if (largest != i) {
  139. Swap(i, largest);
  140. Heapify(largest);
  141. }
  142. }
  143. // Inserts (updates) element at subtree rooted at index i.
  144. int Insert(const Value &value, int i) {
  145. int p;
  146. while (i > 0 && !comp_(values_[p = Parent(i)], value)) {
  147. Swap(i, p);
  148. i = p;
  149. }
  150. return key_[i];
  151. }
  152. private:
  153. const Compare comp_;
  154. std::vector<int> pos_;
  155. std::vector<int> key_;
  156. std::vector<Value> values_;
  157. int size_;
  158. };
  159. } // namespace fst
  160. #endif // FST_HEAP_H_