Priority Queue implementation - logical error in C++? - c++

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?

Related

C++ insert an element to a vector

I am trying to build a priority queue using a vector that stores each element. Firstly, I wanna insert the element to the vector with its priority. I am not sure if it is possible, if not, Can someone give me another solution.
Here is my code:
template <typename E>
class PriorityQueue {
private:
std::vector<E> elements;
E value;
int pr;
public:
PriorityQueue() {}
void insert(int priority, E element) {
}
};
Here is how to create an element with priority for vector:
struct PriElement
{
int data;
int pri;
bool operator < ( const PriElement & other ) const
{
return pri < other.pri;
}
};
vector<PriElement> _vector;
However, the real problem is to keep the vector sorted per priority.
Here is a naive implementation showing the bubble up method:
class PriorityQueue{
public:
void insert( int data, int pri )
{
_vector.push_back(PriElement(data,pri));
int index = _vector.size() -1;
while ( ( index > 0 )&& (_vector[index] < _vector[index-1] ) )
{
swap(_vector[index],_vector[index-1]);
index--;
}
}
private:
vector<PriElement> _vector;
};
For any real world implementation, as mentioned, use priority_queue.
The standard algorithm (see Introduction To Algorithms chapter 6) for doing this is as follows:
When pushing an item, insert it to the end of the vector, then "bubble" it up to the correct place.
When popping the smallest item, replace the first item (at position 0) with the the item at the end, then "bubble" it down to the correct place.
It's possible to show that this can be done with (amortized) logarithmic time (the amortization is due to the vector possibly doubling itself).
However, there is no need to implement this yourself, as the standard library contains std::priority_queue which is a container adapter using std::vector as its default sequence container. For example, if you define
std::priority_queue<int> q;
then q will be a priority queue adapting a vector.

Priority queue in C++ is out of order after pop()

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.

How to implement O(1) deletion on min-heap with hashtable

Read the following statement somewhere:
An additional hash table can be used to make deletion fast in
min-heap.
Question> How to combine priority_queue and unordered_map so that I can implement the idea above?
#include <queue>
#include <unordered_map>
#include <iostream>
#include <list>
using namespace std;
struct Age
{
Age(int age) : m_age(age) {}
int m_age;
};
// Hash function for Age
class HashAge {
public:
const size_t operator()(const Age &a) const {
return hash<int>()(a.m_age);
}
};
struct AgeGreater
{
bool operator()(const Age& lhs, const Age& rhs) const {
return lhs.m_age < rhs.m_age;
}
};
int main()
{
priority_queue<Age, list<Age>, AgeGreater> min_heap; // doesn't work
//priority_queue<Age, vector<Age>, AgeGreater> min_heap;
// Is this the right way to do it?
unordered_map<Age, list<Age>::iterator, HashAge > hashTable;
}
Question> I am not able to make the following work:
priority_queue<Age, list<Age>, AgeGreater> min_heap; // doesn't work
I have to use list as the container b/c the iterators of list is not affected by insertion/deletion (Iterator invalidation rules)
You can't do this with the supplied priority_queue data structure:
In a priority queue you don't know where the elements are stored, so it is hard to delete them in constant time, because you can't find the elements. But, if you maintain a hash table with the location of every element in the priority queue stored in the hash table, then you can find and remove an item quickly, although I would expect log(N) time in the worst case, not constant time. (I don't recall offhand if you get amortized constant time.)
To do this you usually need to roll your own data structures, because you have to update the hash table each time an item is moved around in the priority queue.
I have some example code that does this here:
http://code.google.com/p/hog2/source/browse/trunk/algorithms/AStarOpenClosed.h
It's based on older coding styles, but it does the job.
To illustrate:
/**
* Moves a node up the heap. Returns true if the node was moved, false otherwise.
*/
template<typename state, typename CmpKey, class dataStructure>
bool AStarOpenClosed<state, CmpKey, dataStructure>::HeapifyUp(unsigned int index)
{
if (index == 0) return false;
int parent = (index-1)/2;
CmpKey compare;
if (compare(elements[theHeap[parent]], elements[theHeap[index]]))
{
// Perform normal heap operations
unsigned int tmp = theHeap[parent];
theHeap[parent] = theHeap[index];
theHeap[index] = tmp;
// Update the element location in the hash table
elements[theHeap[parent]].openLocation = parent;
elements[theHeap[index]].openLocation = index;
HeapifyUp(parent);
return true;
}
return false;
}
Inside the if statement we do the normal heapify operations on the heap and then update the location in the hash table (openLocation) to point to the current location in the priority queue.

Assertion error on priority queue with custom class pointers

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.

implement a queue

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.