I'm implementing a A* search algorithm but I keep running into problems with the priority queue. I have implemented a custom comparator for the priority queue according to this article
This is the relevant code:
class CNode;
struct CompareNode : public binary_function<CNode*, CNode*, bool> {
bool operator()(const CNode* lhs, const CNode* rhs) const {
return lhs->m_costFromStart+lhs->m_heuristic > rhs->m_costFromStart+rhs->m_heuristic;
}
};
bool AStarSearch(CNode* start, CNode* end) {
priority_queue<CNode*, vector<CNode*>, CompareNode> open;
...
}
Call stack:
std::_Debug_heap ...
std::pop_heap ...
std::priority_queue<CNode *,std::vector<CNode *,std::allocator<CNode *> >,CompareNode>::pop()
AStarSearch(CNode * start=0x0f9a23b8, CNode * end=0x0f9a24e8)
Greater then was used as I needed a min heap for this algorithm.
The implementation seems to work fine and the problem goes away when it is run in release mode but the priority queue occasionally throws "Invalid heap" assertion failures in debug mode when the priority queue is pop()ed.
I'm not familiar with binary_function in stl but the problem seems to lie with the comparator. Removing the comparator or changing the sign to less then removes the error but that would give me a max heap. Is there something I'm missing?
Thanks for the help. Turns out I did not rebuild the heap after changing the cost of nodes in the priority queue. Calling
make_heap(const_cast<CNode**>(&open.top()), const_cast<CNode**>(&open.top()) + open.size(),
CompareNode());
after every modification to the pq solved the problem.
Related
When configured for mutability, boost::heap::d_ary_heap uses a std::list in addition to the vector that holds the values of the heap nodes. I realize that the handles which are being provided for making the mutable_heap_interface work are in fact iterators of this list, but I'm wondering why such an expensive solution was chosen, and if there's a leaner way to achieve mutability with boost::heap::d_ary_heap.
Mutability requires a way to find the index of a node in the heap vector, given the node itself. Some kind of backward pointer needs to be maintained. Can't this be achieved by storing this backwards pointer in the node, and maintain it by the move/copy constructors/assignment-operators of the value type?
Is there a good reason why it needs to be as expensive as a doubly-linked list?
This is kind of an answer to my own question that only speculates why the boost design is as it is, and presents a partial solution to what I would have liked to get with the boost data structure. I'm still interested in receiving further insight into the rationale behind the boost implementation, and of course also feedback on the solution I present below.
Let me first explain the piece of code below, before going on to discuss its merits and problems, and then comment on the boost.heap implementation, why it presumably is like it is, and why I don't like it.
The code below is based on the venerable std::priority_queue. It splits the node managed by the priority queue into a handle and a body. The handle goes into the heap at the core of the priority_queue, and therefore moves around in the underlying vector as entries are added or removed. The handle only contains the priority value and a pointer to the body, in order to make it cheap to move it around. The body is a potentially large object that remains stationary in memory. It holds a backpointer to the handle, because the handle must be invalidated when the body's priority changes, or the body disappears.
Since the handle moves around in the heap, the backpointer in the body must be updated each time the handle changes location. This is done in the move constructor and the move assignment operator of the handle. If a handle gets invalidated, both the pointer in it and the backpointer pointing at it are nulled.
#include <queue>
//! Priority queue that works with handles to managed objects.
template<typename Prio, typename Object> struct PriorityQueue {
struct Entry;
//! Each heap entry is a handle, consisting of a pointer to the managed object and a priority value.
struct Entry {
Object *obj_;
Prio val_;
Entry(Entry const &) =delete;
Entry &operator=(Entry const &) =delete;
~Entry() {
if(obj_)
obj_->setLink(nullptr);
}
Entry(Object &obj, Prio val)
: obj_{&obj}
, val_{val}
{
if(obj_)
obj_->setLink(this);
}
Entry(Entry &&v)
: obj_{v.obj_}
, val_{v.val_}
{
if(obj_)
obj_->setLink(this);
v.obj_ = nullptr;
}
Entry &operator=(Entry &&v) {
if(&v != this) {
val_ = v.val_;
if(obj_)
obj_->setLink(nullptr);
obj_ = v.obj_;
if(obj_)
obj_->setLink(this);
v.obj_ = nullptr;
}
return *this;
}
friend bool operator<(Entry const &a, Entry const &b) {
return a.val_ < b.val_;
}
};
Prio add(Object &obj, Prio val) {
while(!heap_.empty() && !heap_.top().obj_)
heap_.pop();
heap_.emplace(obj, val);
return heap_.top().val_;
}
Prio remove(Object &obj) {
// We can't remove the entry straight away, so we null the pointer
// and leave the entry in the heap, where it will eventually bubble
// up to the root position, from where it can be removed.
if(obj.getLink()) {
obj.getLink()->obj_ = nullptr;
obj.setLink(nullptr);
}
while(!heap_.empty() && !heap_.top().obj_)
heap_.pop();
return heap_.empty() ? INT64_MAX : heap_.top().val_;
}
Prio update(Object &obj, Prio val) {
remove(obj);
return add(obj, val);
}
std::priority_queue<Entry> heap_;
};
//! Example of a managed object.
struct MyObject {
MyObject(MyObject const &) =delete;
MyObject &operator=(MyObject const &) =delete;
PriorityQueue<int, MyObject>::Entry *getLink() const {
return link_;
}
void setLink(PriorityQueue<int, MyObject>::Entry *link) {
link_ = link;
}
PriorityQueue<int, MyObject>::Entry *link_;
};
Unfortunately, std::priority_queue doesn't support mutability, i.e. you can't remove entries except the root entry, so the fallback is to leave handles in the heap, but invalidate them by breaking the relationship with the body. They will eventually bubble up towards the root, where they can be removed. Obviously, that means that they inflate the size of the heap needlessly, consuming some additional memory and CPU time, which may or may not be significant. If std::priority_queue would expose the internal heap maintenance functions, it would be possible to delete or update entries directly.
It would be possible to reduce the handle size even more by holding the priority in the body rather than the handle, but then the body would need to be consulted for each priority comparison, which would destroy locality of reference. The chosen approach avoids this by holding everything in the handle that is relevant for heap maintenance. The updating of the backpointer in the body by the move constructor and move assignment operator is a write-only operation, which needn't hinder performance, since there typically are write buffers in modern processors that can swallow the associated latency.
For optimizing cache performance, one would wish to use a d-ary heap instead of a binary heap, so that all children of a node (i.e. their handles), which are adjacent in the vector, occupy one cache line. Alas, that's not supported by std::priority_queue, either.
The latter would be supported by boost.heap, but in order to also support mutability, they introduce an additional std::list for the management of the backpointers, which I suspect is rooted in the age of the library. It dates back to before C++11, when move support wasn't yet available in the language. Presumably, only minimal maintenance has been done to it since. I'd welcome them bringing the library up to date and use the opportunity to provide leaner implementations.
So, the bottom line is that I have at least a suspicion that answers my original question, and a design that addresses some of my goals, leaving me with a workable but not yet optimal solution based on the standard library.
Thanks go to the commenters, and remember if you have additional insight to add, you're most welcome.
Is there any inbuilt function for deleting a given element (other than top element) in priority queue class of C++ STL? If not how to delete it in O(log n)?Should i implement the heap data structure from scratch for this 'delete' functionality?
Is there any inbuilt function for deleting a given element (other than top element) in priority queue class of C++ STL?
No.
If not how to delete it in O(log n)?
By using another container. std::set is the simplest compromise. A custom heap implementation may be more optimal.
There is no inbuilt function for deleting a given element(other than top element) in priority queue.
I would recommend you to use std::set which performs the operations in O(logN) by implementing binary tree. But in case you need more better time complexity use std::unordered_set which performs operations in O(1) time and uses hashing.
So my advice will be that use std::set or std::unordered_set & don't restrict yourself to priority queue only.
As suggested by this solution, you can do something like this:
template<typename T>
class custom_priority_queue : public std::priority_queue<T, std::vector<T>>
{
public:
template< typename UnaryPredicate >
T pop_match_or_top(UnaryPredicate p) {
auto it = std::find_if(this->c.begin(), this->c.end(), p);
if (it != this->c.end()) {
T value = std::move(*it);
this->c.erase(it);
std::make_heap(this->c.begin(), this->c.end(), this->comp);
return value;
}
else {
T value = this->top();
this->pop();
return value;
}
}
};
This is specially useful when you need to take elements that are close to the top but are not exactly the top.
I'm trying to compare hsld (integer) in a structure called AdjList.
This is the function to be used for comparisons when entering pointers to the priority queue.
struct CompareHSLD
{
bool operator()(AdjList* const p1, AdjList* const p2)
{
return p1->hsld < p2->hsld;
}
};
This is the priority queue declaration.
priority_queue<AdjList*, vector<AdjList*>, CompareHSLD> PriQueueAdj;
Unable to figure out what the error is in this implementation. There is no syntax error but the priority queue doesn't seem to be sorted. It pops out the wrong elements.
Should it be p1->hsld > p2.hsld if I want to pop the lowest value elements first?
I created a priority queue of Events, which is sorted by Event.time. I inserted 5 events and it worked very well (they are sorted in order of Event.time). However, after I pop(), the remaining queue are out of order (not sorted anymore). Can someone help me explain why ? Thanks a lot.
struct Event
{
string name;
int time;
int pid;
};
class CompareEvent
{
public:
bool operator()(Event& event1, Event& event2)
{
if (event1.time > event2.time)
return true;
return false;
}
};
main class
priority_queue<Event, vector<Event>, CompareEvent> eventList;
Event newEvent;
newEvent.name = eventName;
newEvent.time = time;
newEvent.pid = pid;
eventList.push(newEvent);
eventList.pop(); // the remaining items are not in order anymore
Updated solution: I debugged the program and I looked at the eventList value in the debug windows. The values are not sorted. However, it always return the lowest value when top(). The values are not sorted internally. Thanks for making me realize this.
Priority queue is not required to be sorted. Only requirement is the heap property - if you call pop() or top(), it has to return the top element (the lowest one given the sorting function).
If you need a container that keeps elements sorted, use std::set or std::map.
If you need sorted events at all time, you have to sort or use a sorting container like set or map. The priority_queue only guarantees that pop() returns one of the lowest element (the top) in it.
I have the following queue class (taken from wordpress):
#include<iostream.h>
class Queue
{
private:
int data;
Queue*next;
public:
void Enque(int);
int Deque();
}*head,*tail;
void Queue::enque(int data)
{
Queue *temp;
temp=new Queue;
temp->data=data;
temp->next=NULL;
if(heads==NULL)
heads=temp;
else
tail->next=temp;
tail=temp;
}
int Queue::deque()
{
Queue* temp;//
temp=heads;
heads=heads->next;
return temp->data;
}
I'm trying to figure out why the compiler tells me that I have a multiple definition
of "head" and "tail"- without success.
edit: When the compiler gives the error message it opens up a locale_facets.tcc file
from I-don't-know-where and says that the error is on line 2497 in the following function:
bool
__verify_grouping(const char* __grouping, size_t __grouping_size,
const string& __grouping_tmp)
Does anyone have any insights?
Since this is homework, here is some information about queues and how you could go about implementing one.
A Queue is a standard Abstract Data Type.
It has several properties associated with it:
It is a linear data structure - all components are arranged in a straight line.
It has a grow/decay rule - queues add and remove from opposite ends.
Knowledge of how they're constructed shouldn't be integral in using them because they have public interfaces available.
Queues can be modeled using Sequential Arrays or Linked-Lists.
If you're using an array there are some things to consider because you grow in one direction so you will eventually run out of array. You then have some choices to make (shift versus grow). If you choose to shift back to the beginning of the array (wrap around) you have to make sure the head and tail don't overlap. If you choose to simply grow the queue, you have a lot of wasted memory.
If you're using a Linked-List, you can insert anywhere and the queue will grow from the tail and shrink from the head. You also don't have to worry about filling up your list and having to wrap/shift elements or grow.
However you decide to implement the queue, remember that Queues should provide some common interface to use the queue. Here are some examples:
enqueue - Inserts an element at the back (tail) of the queue
dequeue - Remove an element from the front (head) of a non-empty queue.
empty - Returns whether the queue is empty or not
size - Returns the size of the queue
There are other operations you might want to add to your queue (In C++, you may want an iterator to the front/back of your queue) but how you build your queue should not make a difference with regards to the operations it provides.
However, depending on how you want to use your queue, there are better ways to build it. The usual tradeoff is insert/removal time versus search time. Here is a decent reference.
If your assignment is not directly related to queue implementation, you might want to use the built in std::queue class in C++:
#include <queue>
void test() {
std::queue<int> myQueue;
myQueue.push(10);
if (myQueue.size())
myQueue.pop();
}
Why don't you just use the queue in standard C++ library?
#include <queue>
using namespace std;
int main() {
queue<int> Q;
Q.push(1);
Q.push(2);
Q.push(3);
Q.top(); // 1
Q.top(); // 1 again, we need to pop
Q.pop(); // void
Q.top(); // 2
Q.pop();
Q.top(); // 3
Q.pop();
Q.empty(); // true
return 0;
}
There are a couple of things wrong:
Your methods are declared as Enqueue and Dequeue, but defined as enqueue and dequeue: C++ is case sensitive.
Your methods refer to "heads" which doesn't appear to exist, do you mean "head"?
If you need this for BFS... just use deque.
#include <deque>
using namespace std;
void BFS() {
deque<GraphNode*> to_visit;
to_visit.push_back(start_node);
while (!to_visit.empty()) {
GraphNode* current = to_visit.front();
current->visit(&to_visit); // enqueues more nodes to visit with push_back
to_visit.pop_front();
}
}
The GraphNode::visit method should do all your "work" and add more nodes to the queue to visit. the only methods you should need are push_back(), front(), and pop_front()
This is how I always do it. Hope this helps.
It looks like your problem might have something to do with the fact that:
class Queue {
// blah
} *head, * tail;
is defining a Queue class, and declaring head and tail as type Queue*. They do not look like members of the class, which they should be.