Use boost::heap::d_ary_heap

This commit is contained in:
Michael Krasnyk 2017-05-02 09:10:05 +02:00 committed by Patrick Niklaus
parent 5827358a1e
commit 05826150f6

View File

@ -2,6 +2,7 @@
#define BINARY_HEAP_H #define BINARY_HEAP_H
#include <boost/assert.hpp> #include <boost/assert.hpp>
#include <boost/heap/d_ary_heap.hpp>
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
@ -142,50 +143,38 @@ class BinaryHeap
void Clear() void Clear()
{ {
heap.resize(1); heap.clear();
inserted_nodes.clear(); inserted_nodes.clear();
heap[0].weight = std::numeric_limits<Weight>::min();
node_index.Clear(); node_index.Clear();
} }
std::size_t Size() const { return (heap.size() - 1); } std::size_t Size() const { return heap.size(); }
bool Empty() const { return 0 == Size(); } bool Empty() const { return 0 == Size(); }
void Insert(NodeID node, Weight weight, const Data &data) void Insert(NodeID node, Weight weight, const Data &data)
{ {
HeapElement element; const auto index = static_cast<Key>(inserted_nodes.size());
element.index = static_cast<NodeID>(inserted_nodes.size()); const auto handle = heap.push(std::make_pair(weight, index));
element.weight = weight; inserted_nodes.emplace_back(node, handle, weight, data);
const Key key = static_cast<Key>(heap.size()); node_index[node] = index;
heap.emplace_back(element);
inserted_nodes.emplace_back(node, key, weight, data);
node_index[node] = element.index;
Upheap(key);
CheckHeap();
} }
Data &GetData(NodeID node) Data &GetData(NodeID node)
{ {
const Key index = node_index.peek_index(node); const auto index = node_index.peek_index(node);
return inserted_nodes[index].data; return inserted_nodes[index].data;
} }
Data const &GetData(NodeID node) const Data const &GetData(NodeID node) const
{ {
const Key index = node_index.peek_index(node); const auto index = node_index.peek_index(node);
return inserted_nodes[index].data; return inserted_nodes[index].data;
} }
Weight &GetKey(NodeID node)
{
const Key index = node_index[node];
return inserted_nodes[index].weight;
}
const Weight &GetKey(NodeID node) const const Weight &GetKey(NodeID node) const
{ {
const Key index = node_index.peek_index(node); const auto index = node_index.peek_index(node);
return inserted_nodes[index].weight; return inserted_nodes[index].weight;
} }
@ -193,7 +182,7 @@ class BinaryHeap
{ {
BOOST_ASSERT(WasInserted(node)); BOOST_ASSERT(WasInserted(node));
const Key index = node_index.peek_index(node); const Key index = node_index.peek_index(node);
return inserted_nodes[index].key == 0; return inserted_nodes[index].handle == HeapHandle{};
} }
bool WasInserted(const NodeID node) const bool WasInserted(const NodeID node) const
@ -208,132 +197,67 @@ class BinaryHeap
NodeID Min() const NodeID Min() const
{ {
BOOST_ASSERT(heap.size() > 1); BOOST_ASSERT(!heap.empty());
return inserted_nodes[heap[1].index].node; return inserted_nodes[heap.top().second].node;
} }
Weight MinKey() const Weight MinKey() const
{ {
BOOST_ASSERT(heap.size() > 1); BOOST_ASSERT(!heap.empty());
return heap[1].weight; return heap.top().first;
} }
NodeID DeleteMin() NodeID DeleteMin()
{ {
BOOST_ASSERT(heap.size() > 1); BOOST_ASSERT(!heap.empty());
const Key removedIndex = heap[1].index; const Key removedIndex = heap.top().second;
heap[1] = heap[heap.size() - 1]; heap.pop();
heap.pop_back(); inserted_nodes[removedIndex].handle = HeapHandle{};
if (heap.size() > 1)
{
Downheap(1);
}
inserted_nodes[removedIndex].key = 0;
CheckHeap();
return inserted_nodes[removedIndex].node; return inserted_nodes[removedIndex].node;
} }
void DeleteAll() void DeleteAll()
{ {
auto iend = heap.end(); std::for_each(inserted_nodes.begin(), inserted_nodes.end(), [](auto &node) {
for (auto i = heap.begin() + 1; i != iend; ++i) node.handle = HeapHandle();
{ });
inserted_nodes[i->index].key = 0; heap.clear();
}
heap.resize(1);
heap[0].weight = (std::numeric_limits<Weight>::min)();
} }
void DecreaseKey(NodeID node, Weight weight) void DecreaseKey(NodeID node, Weight weight)
{ {
BOOST_ASSERT(std::numeric_limits<NodeID>::max() != node); BOOST_ASSERT(!WasRemoved(node));
const Key &index = node_index.peek_index(node); const auto index = node_index.peek_index(node);
Key &key = inserted_nodes[index].key; auto &reference = inserted_nodes[index];
BOOST_ASSERT(key >= 0); reference.weight = weight;
heap.increase(reference.handle, std::make_pair(weight, index));
inserted_nodes[index].weight = weight;
heap[key].weight = weight;
Upheap(key);
CheckHeap();
} }
private: private:
using HeapData = std::pair<Weight, Key>;
using HeapContainer = boost::heap::d_ary_heap<HeapData,
boost::heap::arity<4>,
boost::heap::mutable_<true>,
boost::heap::compare<std::greater<HeapData>>>;
using HeapHandle = typename HeapContainer::handle_type;
class HeapNode class HeapNode
{ {
public: public:
HeapNode(NodeID n, Key k, Weight w, Data d) : node(n), key(k), weight(w), data(std::move(d)) HeapNode(NodeID n, HeapHandle h, Weight w, Data d)
: node(n), handle(h), weight(w), data(std::move(d))
{ {
} }
NodeID node; NodeID node;
Key key; HeapHandle handle;
Weight weight; Weight weight;
Data data; Data data;
}; };
struct HeapElement
{
Key index;
Weight weight;
};
std::vector<HeapNode> inserted_nodes; std::vector<HeapNode> inserted_nodes;
std::vector<HeapElement> heap; HeapContainer heap;
IndexStorage node_index; IndexStorage node_index;
void Downheap(Key key)
{
const Key droppingIndex = heap[key].index;
const Weight weight = heap[key].weight;
const Key heap_size = static_cast<Key>(heap.size());
Key nextKey = key << 1;
while (nextKey < heap_size)
{
const Key nextKeyOther = nextKey + 1;
if ((nextKeyOther < heap_size) && (heap[nextKey].weight > heap[nextKeyOther].weight))
{
nextKey = nextKeyOther;
}
if (weight <= heap[nextKey].weight)
{
break;
}
heap[key] = heap[nextKey];
inserted_nodes[heap[key].index].key = key;
key = nextKey;
nextKey <<= 1;
}
heap[key].index = droppingIndex;
heap[key].weight = weight;
inserted_nodes[droppingIndex].key = key;
}
void Upheap(Key key)
{
const Key risingIndex = heap[key].index;
const Weight weight = heap[key].weight;
Key nextKey = key >> 1;
while (heap[nextKey].weight > weight)
{
BOOST_ASSERT(nextKey != 0);
heap[key] = heap[nextKey];
inserted_nodes[heap[key].index].key = key;
key = nextKey;
nextKey >>= 1;
}
heap[key].index = risingIndex;
heap[key].weight = weight;
inserted_nodes[risingIndex].key = key;
}
void CheckHeap()
{
#ifndef NDEBUG
for (std::size_t i = 2; i < heap.size(); ++i)
{
BOOST_ASSERT(heap[i].weight >= heap[i >> 1].weight);
}
#endif
}
}; };
} }
} }