1
0
Fork 0
maximum-weight-matching/cpp/priority_queue.hpp

267 lines
6.4 KiB
C++

/**
* Priority queue data structure.
*/
#ifndef MWMATCHING_PRIORITY_QUEUE_H_
#define MWMATCHING_PRIORITY_QUEUE_H_
#include <cassert>
#include <limits>
#include <vector>
namespace mwmatching {
/**
* Min-priority queue implemented as a binary heap.
*
* Elements in a heap have a priority and associated "data".
*
* The following operations can be done efficiently:
* - Insert an element into the queue.
* - Remove an element from the queue.
* - Change the priority of a given element.
* - Find the element with lowest priority in the queue.
*/
template <typename PrioType,
typename DataType>
class PriorityQueue
{
public:
typedef unsigned int IndexType;
static constexpr IndexType INVALID_INDEX =
std::numeric_limits<IndexType>::max();
/**
* A Node instance represents an element in a PriorityQueue.
*
* A Node instance must remain valid while it is contained in a queue.
* The containing queue holds a pointer to the Node.
*
* A Node instance may be destructed if it is not contained in any queue.
* Alternatively, a Node instance may be destructed after its containing
* queue instance has been destructed.
*/
class Node
{
public:
/** Construct an invalid node, not contained in any queue. */
Node()
: index_(INVALID_INDEX)
{ }
// Prevent copying.
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
/** Return true if this node is contained in a queue. */
bool valid() const
{
return (index_ != INVALID_INDEX);
}
/**
* Return the priority of this node in the queue.
*
* The node must be contained in a queue.
* This function takes time O(1).
*/
PrioType prio() const
{
assert(index_ != INVALID_INDEX);
return prio_;
}
private:
IndexType index_;
PrioType prio_;
DataType data_;
friend class PriorityQueue;
};
/** Construct an empty queue. */
PriorityQueue()
{ }
// Prevent copying.
PriorityQueue(const PriorityQueue&) = delete;
PriorityQueue& operator=(const PriorityQueue&) = delete;
/**
* Remove all elements from the queue.
*
* This function takes time O(n).
*/
void clear()
{
for (Node* node : heap_) {
node->index_ = INVALID_INDEX;
}
heap_.clear();
}
/** Return true if the queue is empty. */
bool empty() const
{
return heap_.empty();
}
/**
* Return the minimum priority of any element in the queue.
*
* The queue must be non-empty.
* This function takes time O(1).
*/
PrioType min_prio() const
{
assert(! heap_.empty());
Node* top = heap_.front();
return top->prio_;
}
/**
* Return the element with minimum priority.
*
* The queue must be non-empty.
* This function takes time O(1).
*/
DataType min_elem() const
{
assert(! heap_.empty());
Node* top = heap_.front();
return top->data_;
}
/**
* Insert the given node into the queue with associated data.
*
* The node must not currently be contained in any queue.
* This function takes amortized time O(log(n)).
*/
void insert(Node* node, PrioType prio, const DataType& data)
{
assert(node->index_ == INVALID_INDEX);
node->index_ = heap_.size();
node->prio_ = prio;
node->data_ = data;
heap_.push_back(node);
sift_up(node->index_);
}
/**
* Update priority of an existing node.
*
* This function takes time O(log(n)).
*/
void set_prio(Node* node, PrioType prio)
{
IndexType index = node->index_;
assert(index != INVALID_INDEX);
assert(heap_[index] == node);
PrioType prev_prio = node->prio_;
node->prio_ = prio;
if (prio < prev_prio) {
sift_up(index);
} else if (prio > prev_prio) {
sift_down(index);
}
}
/**
* Remove the specified element from the queue.
*
* This function takes time O(log(n)).
*/
void remove(Node* node)
{
IndexType index = node->index_;
assert(index != INVALID_INDEX);
assert(heap_[index] == node);
node->index_ = INVALID_INDEX;
Node* move_node = heap_.back();
heap_.pop_back();
if (index < heap_.size()) {
heap_[index] = move_node;
move_node->index_ = index;
if (move_node->prio_ < node->prio_) {
sift_up(index);
} else if (move_node->prio_ > node->prio_) {
sift_down(index);
}
}
}
private:
/** Repair the heap along an ascending path to the root. */
void sift_up(IndexType index)
{
Node* node = heap_[index];
PrioType prio = node->prio_;
while (index > 0) {
IndexType next_index = (index - 1) / 2;
Node* next_node = heap_[next_index];
if (next_node->prio_ <= prio) {
break;
}
heap_[index] = next_node;
next_node->index_ = index;
index = next_index;
}
node->index_ = index;
heap_[index] = node;
}
/** Repair the heap along a descending path. */
void sift_down(IndexType index)
{
Node* node = heap_[index];
PrioType prio = node->prio_;
IndexType num_elem = heap_.size();
while (index < num_elem / 2) {
IndexType next_index = 2 * index + 1;
Node* next_node = heap_[next_index];
if (next_index + 1 < num_elem) {
Node* tmp_node = heap_[next_index + 1];
if (tmp_node->prio_ <= next_node->prio_) {
++next_index;
next_node = tmp_node;
}
}
if (next_node->prio_ >= prio) {
break;
}
heap_[index] = next_node;
next_node->index_ = index;
index = next_index;
}
heap_[index] = node;
node->index_ = index;
}
/** Heap data structure. */
std::vector<Node*> heap_;
};
} // namespace mwmatching
#endif // MWMATCHING_PRIORITY_QUEUE_H_