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

// Copyright 2005-2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the 'License');
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an 'AS IS' BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// See www.openfst.org for extensive documentation on this weighted
// finite-state transducer library.
//
// Implementation of a heap as in STL, but allows tracking positions in heap
// using a key. The key can be used to do an in-place update of values in the
// heap.
#ifndef FST_HEAP_H_
#define FST_HEAP_H_
#include <utility>
#include <vector>
#include <fst/compat.h>
#include <fst/log.h>
namespace fst {
// A templated heap implementation that supports in-place update of values.
//
// The templated heap implementation is a little different from the STL
// priority_queue and the *_heap operations in STL. This heap supports
// indexing of values in the heap via an associated key.
//
// Each value is internally associated with a key which is returned to the
// calling functions on heap insert. This key can be used to later update
// the specific value in the heap.
//
// T: the element type of the hash. It can be POD, Data or a pointer to Data.
// Compare: comparison functor for determining min-heapness.
template <class T, class Compare>
class Heap {
public:
using Value = T;
static constexpr int kNoKey = -1;
// Initializes with a specific comparator.
explicit Heap(Compare comp = Compare()) : comp_(comp), size_(0) {}
// Inserts a value into the heap.
int Insert(const Value &value) {
if (size_ < values_.size()) {
values_[size_] = value;
pos_[key_[size_]] = size_;
} else {
values_.push_back(value);
pos_.push_back(size_);
key_.push_back(size_);
}
++size_;
return Insert(value, size_ - 1);
}
// Updates a value at position given by the key. The pos_ array is first
// indexed by the key. The position gives the position in the heap array.
// Once we have the position we can then use the standard heap operations
// to calculate the parent and child positions.
void Update(int key, const Value &value) {
const auto i = pos_[key];
const bool is_better = comp_(value, values_[Parent(i)]);
values_[i] = value;
if (is_better) {
Insert(value, i);
} else {
Heapify(i);
}
}
// Returns the least value.
Value Pop() {
DCHECK(!Empty());
Value top = values_.front();
Swap(0, size_ - 1);
size_--;
Heapify(0);
return top;
}
// Returns the least value w.r.t. the comparison function from the
// heap.
const Value &Top() const {
DCHECK(!Empty());
return values_.front();
}
// Returns the element for the given key.
const Value &Get(int key) const {
DCHECK_LT(key, pos_.size());
return values_[pos_[key]];
}
// Checks if the heap is empty.
bool Empty() const { return size_ == 0; }
void Clear() { size_ = 0; }
int Size() const { return size_; }
void Reserve(int size) {
values_.reserve(size);
pos_.reserve(size);
key_.reserve(size);
}
const Compare &GetCompare() const { return comp_; }
private:
// The following private routines are used in a supportive role
// for managing the heap and keeping the heap properties.
// Computes left child of parent.
static int Left(int i) {
return 2 * (i + 1) - 1; // 0 -> 1, 1 -> 3
}
// Computes right child of parent.
static int Right(int i) {
return 2 * (i + 1); // 0 -> 2, 1 -> 4
}
// Given a child computes parent.
static int Parent(int i) {
return (i - 1) / 2; // 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 1, 4 -> 1, ...
}
// Swaps a child and parent. Use to move element up/down tree. Note the use of
// a little trick here. When we swap we need to swap:
//
// - the value
// - the associated keys
// - the position of the value in the heap
void Swap(int j, int k) {
const auto tkey = key_[j];
pos_[key_[j] = key_[k]] = j;
pos_[key_[k] = tkey] = k;
using std::swap;
swap(values_[j], values_[k]);
}
// Heapifies the subtree rooted at index i.
void Heapify(int i) {
const auto l = Left(i);
const auto r = Right(i);
auto largest = (l < size_ && comp_(values_[l], values_[i])) ? l : i;
if (r < size_ && comp_(values_[r], values_[largest])) largest = r;
if (largest != i) {
Swap(i, largest);
Heapify(largest);
}
}
// Inserts (updates) element at subtree rooted at index i.
int Insert(const Value &value, int i) {
int p;
while (i > 0 && !comp_(values_[p = Parent(i)], value)) {
Swap(i, p);
i = p;
}
return key_[i];
}
private:
const Compare comp_;
std::vector<int> pos_;
std::vector<int> key_;
std::vector<Value> values_;
int size_;
};
} // namespace fst
#endif // FST_HEAP_H_