1
0
Fork 0

New version of PriorityQueue.

This commit is contained in:
Max Neunhoeffer 2015-04-23 19:56:18 -07:00
parent 570509a58a
commit 4bdcfdb238
1 changed files with 63 additions and 16 deletions

View File

@ -45,11 +45,16 @@ namespace triagens {
// store with the additional property that every Value has a
// positive Weight (provided by the weight() and setWeight(w)
// methods), which is a numerical type, and for which operator<
// is defined. Furthermore, the Value type must be copyable and
// movable. Finally, the Value type must have a method getKey that
// returns a Key const&.
// is defined. With respect to this weight the data structure
// is at the same time a priority queue in that it is possible
// to ask for (one of) the value(s) with the smallest weight and
// remove this efficiently.
// The Value type must be copyable and should be movable. Finally,
// the Value type must have a method getKey that returns a Key
// const&.
// This data structure makes the following complexity promises
// (amortized), where n is the number of key/value pairs stored:
// (amortized), where n is the number of key/value pairs stored
// in the queue:
// insert: O(log(n)) (but see below)
// lookup value by key: O(1)
// get smallest: O(1)
@ -60,6 +65,10 @@ namespace triagens {
// and if we do not use lower weight by key, then we even get:
// insert: O(1)
// get and erase smallest: O(1)
// With the "get and erase smallest" operation one has the option
// of retaining the erased value in the key/value store. It can then
// still be looked up but will no longer be considered for the
// priority queue.
public:
@ -119,7 +128,8 @@ namespace triagens {
}
_heap.push_back(v);
try {
_lookup.insert(std::make_pair(k, _heap.size()-1 + _popped));
_lookup.insert(std::make_pair(k,
static_cast<ssize_t>(_heap.size()-1 + _popped)));
}
catch (...) {
_heap.pop_back();
@ -132,7 +142,8 @@ namespace triagens {
_heap.push_back(v);
try {
size_t newpos = _heap.size() - 1;
_lookup.insert(std::make_pair(k, newpos + _popped));
_lookup.insert(std::make_pair(k,
static_cast<ssize_t>(newpos + _popped)));
repairUp(newpos);
}
catch (...) {
@ -151,7 +162,14 @@ namespace triagens {
if (it == _lookup.end()) {
return nullptr;
}
return const_cast<Value const*>(&(_heap[it->second - _popped]));
if (it->second >= 0) { // still in the queue
return const_cast<Value const*>
(&(_heap[static_cast<size_t>(it->second) - _popped]));
}
else { // already in the history
return const_cast<Value const*>
(&(_history[static_cast<size_t>(-it->second) - 1]));
}
}
////////////////////////////////////////////////////////////////////////////////
@ -166,9 +184,15 @@ namespace triagens {
if (it == _lookup.end()) {
return false;
}
size_t pos = it->second - _popped;
_heap[pos].setWeight(newWeight);
repairUp(pos);
if (it->second >= 0) { // still in the queue
size_t pos = static_cast<size_t>(it->second) - _popped;
_heap[pos].setWeight(newWeight);
repairUp(pos);
}
else { // already in the history
size_t pos = static_cast<size_t>(-it->second) - 1;
_history[pos].setWeight(newWeight);
}
return true;
}
@ -188,18 +212,28 @@ namespace triagens {
/// if the structure is empty. Key and Value are stored in k and v.
////////////////////////////////////////////////////////////////////////////////
bool popMinimal (Key& k, Value& v) {
bool popMinimal (Key& k, Value& v, bool keepForLookup = false) {
if (_heap.empty()) {
return false;
}
k = _heap[0].getKey();
v = _heap[0];
if (! _isHeap) {
auto it = _lookup.find(k);
TRI_ASSERT(it != _lookup.end());
if (keepForLookup) {
_history.push_back(_heap[0]);
it->second = -static_cast<ssize_t>(_history.size());
// Note: This is intentionally one too large to shift by 1
}
else {
_lookup.erase(it);
}
_heap.pop_front();
_popped++;
}
else {
removeFromHeap();
removeFromHeap(keepForLookup);
}
return true;
}
@ -319,7 +353,7 @@ namespace triagens {
/// @brief removeFromHeap, remove first position in the heap
////////////////////////////////////////////////////////////////////////////////
void removeFromHeap () {
void removeFromHeap (bool keepForLookup) {
if (_heap.size() == 1) {
_heap.clear();
_popped = 0;
@ -331,12 +365,19 @@ namespace triagens {
auto it = _lookup.find(_heap[0].getKey());
TRI_ASSERT(it != _lookup.end());
_lookup.erase(it);
if (keepForLookup) {
_history.push_back(_heap[0]);
it->second = -static_cast<ssize_t>(_history.size());
// Note: This is intentionally one too large to shift by 1
}
else {
_lookup.erase(it);
}
_heap[0] = _heap.back();
_heap.pop_back();
it = _lookup.find(_heap[0].getKey());
TRI_ASSERT(it != _lookup.end());
it->second = _popped;
it->second = static_cast<ssize_t>(_popped);
repairDown();
}
@ -357,7 +398,7 @@ namespace triagens {
/// @brief _lookup, this provides O(1) lookup by Key
////////////////////////////////////////////////////////////////////////////////
std::unordered_map<Key, size_t> _lookup;
std::unordered_map<Key, ssize_t> _lookup;
////////////////////////////////////////////////////////////////////////////////
/// @brief _isHeap, starts as false, in which case we only use a deque,
@ -379,6 +420,12 @@ namespace triagens {
Weight _maxWeight;
////////////////////////////////////////////////////////////////////////////////
/// @brief _history, the actual data that is only in the key/value store
////////////////////////////////////////////////////////////////////////////////
std::vector<Value> _history;
};
class Traverser {