This site suggests that if I want to reverse-order my priority queues, the following code is what I should use:
#include <iostream>
#include <queue>
using namespace std;
class mycomparison{
bool reverse;
public:
mycomparison(const bool &revparam=false) {reverse=revparam;}
bool operator() (const int &lhs, const int &rhs) const {
if (reverse) return (lhs>rhs);
else return (lhs<rhs);
}
};
int main (){
int myints[]= {10,60,50,20};
priority_queue<int, vector<int>, mycomparison(true)> first;
return 0;
}
This bothers me:
I have to specify the storage class in my constructor.
I have created a class whose only purpose is to be passed to the priority queue.
Is there a more elegant or less verbose way of reverse-sorting a priority queue?
You can't avoid specifying the storage container, but you can avoid writing your own functor:
priority_queue<int, vector<int>, std::greater<int> > first;
If you want flexibility without having to define any class, you could use std::function> as the type of your comparator:
#include <functional>
int main ()
{
int myints[]= {10,60,50,20};
// Use this is a the type of your comparator
typedef std::function<bool(int, int)> comp_type;
// Priority queue using operator < for ordering
priority_queue<int, vector<int>, comp_type> first(std::less<int>());
// ...
// Priority queue using operator > for ordering
priority_queue<int, vector<int>, comp_type> second(std::greater<int>());
// ...
return 0;
}
I have found much more simple solution while I was reversing a priority queue of struct.
I hame modified solution from there: stl priority_queue of C++ with struct
struct leaf
{
int symbol;
double probability;
bool operator < (const leaf &o) const
{
return probability > o.probability; // here just reversed the operator
}
};
priority_queue <leaf> leafs_queue; //queue already reversed
Related
Finding a shortest path in a grid and struggling to set up priority queue properly.
struct position{
int row;
int col;
position* parent;
position(int a, int b):row(a),col(b), parent(nullptr){}
};
vector<position>vec;
priority_queue<pair<int, position>, vector<pair<int, position>>, greater<pair<int, position>>>pq;
int distance = 0;
position *t = new p(0,0);
pq.push(make_pair(distance, t));
Getting this error:
no matching function for call to ‘std::priority_queue, std::vector >, std::greater > >::push(std::pair)’
pq.push(make_pair(distance, t));
You need to write a functor ( or use a lambda) to compare the distance - position pair, std::greater won't automatically do it for you. Try this snippet:
struct position {
int row;
int col;
position* parent;
position(int a, int b) :row(a), col(b), parent(nullptr) {}
};
typedef std::pair<int, position> dist_pos_t;
class compare
{
public:
bool operator()(const dist_pos_t& lhs, const dist_pos_t& rhs)
{
return rhs.first < lhs.first;
}
};
std::priority_queue<dist_pos_t, std::vector<dist_pos_t>, compare >pq;
int main() {
int distance = 0;
position *t = new position(0, 0);
pq.push(std::make_pair(distance, *t));
}
Here Declaration of Priority Queue does not match with what you are trying to push.
Declaration should be something like
priority_queue<pair<obj1,obj2>pq;
obj1/obj2 can be anything like int or pair<obj,obj>
After such declaration you can use
pq.push(make_pair(obj1,obj2))
There are two major issues in your code.
First, your priority_queue is of std::pair<int, position>, but you are trying to push in a std::pair<int, position*>.
Second, std::greater<T> depends on the > operator of the underlying type T. In your case, it's std::pair<int, position>, whose > operator depends on the < operator of position (See this reference). You need to provide < for position, or, you can use a custom compare functor type.
Lets say I have the a class called MyClass and every MyClass object has a method called xVal. What I want is a priority queue of MyClass objects sorted in ascending order of MyClass.xVal()
So far I have this:
priority_queue<MyClass, vector<MyClass>, greater<MyClass>> queue;
Of course, it doesn't do what I expect.I complies but uses some random ordering for my objects. Would appreciate it if someone can point out what I am doing wrong.
Thanks.
The CPP Reference link to Priority Queue provides that a priority queue can be defined as:
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
Here, T=MyClass and Container=std::vector<MyClass>. The only thing that remains is Compare which as has been mentioned above can be implemented using either Lambdas or Functors. I'll show both:
Let's say the class is defined as shown below with xVal() method's return value as the sort key:
struct MyClass{
int count;
int key;
int xVal() { return count; };
};
Using Lambdas
// Lambda skeleton: [capture preferences](arguments){ body }
auto cmp = [](MyClass left, MyClass right) {return left.xVal() > right.xVal();};
std::priority_queue<MyClass, std::vector<MyClass>, decltype(cmp)> queue(cmp);
Using a Functor
struct CmpFunctor{
bool operator()(MyClass left, MyClass right) const {
return left.xVal() > right.xVal();
}
};
auto cmp = CmpFunctor()
std::priority_queue<MyClass, std::vector<MyClass>, decltype(cmp)> queue(cmp);
Here is a link showing the running code.
This is my code for Dijkstra's algorithm:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#define pp pair<int,int>
using namespace std;
struct pri
{
int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
return p1.second<p2.second;
}
}p;
int main()
{
priority_queue<pp,vector<pp>,pri> q;
int n;
cin>>n;
vector<pp> g[n+1];
int e,u,v,w,i;
cin>>e;
for(i=0;i<e;i++)
{
cin>>u>>v>>w;
g[u].push_back(pp(v,w));
g[v].push_back(pp(u,w));
}
int s;
cin>>s;
int d[n+1];
for(i=1;i<=n;i++)
d[i]=999;
d[s]=0;
q.push(pp(s,d[s]));
while(!q.empty())
{
u=q.top().first;
q.pop();
int size=g[u].size();
for(int i=0;i<size;i++)
{
v=g[u][i].first;
w=g[u][i].second;
cout<<u<<" "<<" "<<w<<endl;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
q.push(pp(v,d[v]));
}
}
}
for(i=1;i<=n;i++)
printf("node %d,min weight=%d\n",i,d[i]);
return 0;
}
In this I can't understand the working of
priority_queue<pp,vector<pp>,pri> q;
That is related to:
struct pri
{
int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
return p1.second<p2.second;
}
}p;
What is the use of () operator in this? I mean how it functions in this code?
Also why are we using & in operator()?
Also, how does this comparator work in priority queue definition?
And why are we using constant in operator definition?
i mean to say how is exactly this comparison in operator working and cant we use any
other symbol as = * # or any other instead of ()
I think the compare function you write is wrong.
int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
return p1.second<p2.second;
}
which the correct one should be
int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
return p1.second>p2.second;
}
Because in priority_quequeyou can find that The expression comp(a,b), where comp is an object of this type and a and b are elements in the container, shall return true if a is considered to go before b in the strict weak ordering the function defines.
Because in the Dijkstra algorithm, the node with smaller value should has higher priority, thus the operator we used here should be
p1.second>p2.second
(By using your code to solve a problem, it took me a long time to figure out this problem that my program's results were always different with the correct one.)
(By the way, in the Dijkstra algorithm itself, I think once a node was pop as the smallest one, there is no need to pop it again and update all the nodes that connected to it. This could save a lot of time.)
struct pri {
int operator() (const pair<int,int>&p1,const pair<int,int>&p2)
{
return p1.second<p2.second;
}
}p;
Creates a function object by overloading () operator
This is passed to the priority_queue as the compare class
& is used to pass the pair as constant reference, making sure that no copying of actual arguments take place, (by passing them as reference), at same time the function can't modify their values (by using const keyword)
With the use of this function object, the queue determines how to insert the values (pair).
In this case the second value of pair is used for comparison.
When declaring variables (including function arguments), the & is to mark the variable as a reference. It's very basic and common thing to use references for some types of arguments, partly because it passes the arguments without creating copies (so good for e.g. a std::vector) and it also allows non-const references to be changed in the function as a form of output argument.
As for the use of operator() in a structure like this, it makes instances of the structure function objects, in other words, objects that can be invoked like a function.
I think your question is about the line priority_queue<pp,vector<pp>,pri> q;?
This declares a variable q of type priority_queue<pp,vector<pp>,pri>. priority_queue is defined as
template<class T,
class Container = vector<T>,
class Compare = less<typename Container::value_type> >
class priority_queue;
So, pp is the type of the elements, vector<pp> is the container (the same as the default), and pri is a function object which is used to compare items in the queue (Compare). The priority_queue uses Compare to order its elements. If the elements cannot be compared directly, or the default is not appropriate, then you can supply your own. In this case, the elements will be order by second member in each element pair.
Basically the same as the other answers, just a little more detail -- the operator() code is what defines how the priority queue should do comparisons to determine item priority in the queue. Using this type of framework, you can have a priority queue defined to store any type of objects, and the priority queue can be ordered according to any kind of custom ordering you want on the objects.
I refactored this code and checked it with hackerrank.
#include <cstdio>
#include <vector>
#include <queue>
#include <iostream>
#include <vector>
#include <deque>
#include <set>
#include <limits>
#include <iterator>
#include <algorithm>
#include <functional>
using namespace std;
struct pri
{
typedef pair<int,int> pp;
typedef deque<pri::pp > list;
typedef vector< pri::list > graph;
int operator() (pp&p1,const pp&p2)
{
return p1.second>p2.second;
}
typedef priority_queue< pri::pp, pri::list, pri > queue;
};
static int f1(const int x){ return x==std::numeric_limits<int>().max()?-1:x; }
int main()
{
int t;
cin>>t;
while(t--){
int n,e;
cin>>n>>e;
pri::graph g(n+1);
for(int i(0);i<e;i++){
int u,v,w;
cin>>u>>v>>w;
g[u].push_back(pri::pp(v,w));
g[v].push_back(pri::pp(u,w));
}
vector<int> d(n+1,std::numeric_limits<int>().max());
int s; cin>>s;
d[s]=0;
pri::queue q;
q.push(pri::pp(s,d[s]));
set<int> vs;
while(!q.empty()) {
const int u(q.top().first);
const pri::list& gu(g[u]);
q.pop();
vs.insert(u);
for( pri::list::const_iterator i(gu.begin()); i != gu.end(); ++i ) {
const int v(i->first), w(i->second);
if( vs.find(v)==vs.end() ){
// cout<<u<<" "<<v<<" "<<w<<endl;
if( d[v]>d[u]+w ) {
d[v]=d[u]+w;
q.push(pri::pp(v,d[v]));
}
}
}
}
copy_if(d.begin()+1,d.end(),d.begin(),std::bind2nd(std::not_equal_to<int>(),0));
transform(d.begin(),d.end()-2,ostream_iterator<int>(cout," "),f1);
cout<<endl;
}
return 0;
}
I'm trying to declare a priority_queue of nodes, using bool Compare(Node a, Node b) as the comparator function (which is outside the node class).
What I currently have is:
priority_queue<Node, vector<Node>, Compare> openSet;
For some reason, I'm getting Error: "Compare" is not a type name
Changing the declaration to priority_queue <Node, vector<Node>, bool Compare>
gives me Error: expected a '>'
I've also tried:
priority_queue<Node, vector<Node>, Compare()> openSet;
priority_queue<Node, vector<Node>, bool Compare()> openSet;
priority_queue<Node, vector<Node>, Compare<Node, Node>> openSet;
How should I correctly declare my priority_queue?
Note - You may also want to check other answers, especially the one with decltype and lambda
You should declare a class Compare and overload operator() for it like this:
class Foo
{
};
class Compare
{
public:
bool operator() (Foo, Foo)
{
return true;
}
};
int main()
{
std::priority_queue<Foo, std::vector<Foo>, Compare> pq;
return 0;
}
Or, if you for some reasons can't make it as class, you could use std::function for it:
class Foo
{
};
bool Compare(Foo, Foo)
{
return true;
}
int main()
{
std::priority_queue<Foo, std::vector<Foo>, std::function<bool(Foo, Foo)>> pq(Compare);
return 0;
}
The accepted answer shows how to use a class or a std::function as comparator. We can also pass a function pointer, as cute_ptr's answer already showed. However, the syntax to do so is much simpler than shown there:
class Node;
bool Compare(Node a, Node b);
std::priority_queue<Node, std::vector<Node>, decltype(&Compare)> openSet(Compare);
That is, there is no need to explicitly encode the function's type, you can let the compiler do that for you using decltype.
This is very useful if the comparator is a lambda. You cannot specify the type of a lambda in any other way than using decltype. For example:
auto compare = [](Node a, Node b) { return a.foo < b.foo; }
std::priority_queue<Node, std::vector<Node>, decltype(compare)> openSet(compare);
The third template parameter must be a class who has operator()(Node,Node) overloaded.
So you will have to create a class this way:
class ComparisonClass {
public:
bool operator() (Node, Node) {
//comparison code here
}
};
And then you will use this class as the third template parameter like this:
priority_queue<Node, vector<Node>, ComparisonClass> q;
Answering your question directly:
I'm trying to declare a priority_queue of nodes, using bool Compare(Node a, Node b) as the comparator function
What I currently have is:
priority_queue<Node, vector<Node>, Compare> openSet;
For some reason, I'm getting Error:
"Compare" is not a type name
The compiler is telling you exactly what's wrong: Compare is not a type name, but an instance of a function that takes two Nodes and returns a bool.
What you need is to specify the function pointer type:
std::priority_queue<Node, std::vector<Node>, bool (*)(Node, Node)> openSet(Compare)
You have to define the compare first. There are 3 ways to do that:
use class
use struct (which is same as class)
use lambda function.
It's easy to use class/struct because easy to declare just write this line of code above your executing code
struct compare{
public:
bool operator()(Node& a,Node& b) // overloading both operators
{
return a.w < b.w: // if you want increasing order;(i.e increasing for minPQ)
return a.w > b.w // if you want reverse of default order;(i.e decreasing for minPQ)
}
};
Calling code:
priority_queue<Node,vector<Node>,compare> pq;
One can also use a lambda function.
auto Compare = [](Node &a, Node &b) { //compare };
std::priority_queue<Node, std::vector<Node>, decltype(Compare)> openset(Compare);
In case this helps anyone :
static bool myFunction(Node& p1, Node& p2) {}
priority_queue <Node, vector<Node>, function<bool(Node&, Node&)>> pq1(myFunction);
In the priority queue, there is a predefined boolean function "operator<()", try to overload this function as per your requirement.
bool operator<(const Node& x,const Node& y){
return x.data>y.data;
}
priority_queue<Node> min_heap;
With latest c++ standard, you can actually declare a lambda function for comparator which would make the code much cleaner. Here is a sample code:
#include <queue>
class Foo
{
public:
int i;
};
int main()
{
auto comparator = [](const Foo& a, const Foo& b) {
return a.i > b.i;
};
std::priority_queue<Foo, std::vector<Foo>, decltype(comparator)> pq(comparator);
return 0;
}
With the help of struct also we can do this. The code will go something like below.
struct myCompare{
bool operator()(Node &a, Node &b){
// Your own custom logic to compare the two nodes and return a boolean value.
}
}
priority_queue<Node, vector<Node>, myCompare> openSet;
prefer struct, and it's what std::greater do
struct Compare {
bool operator()(Node const&, Node &) {}
}
This is my first time using a priority queue. I'm trying to implement Dijkstra's algorithm for school and I figured I need a min heap to do this. Right now my nodes are pointers and I want to compare their weight, but I don't think I can overload > and < with pointers? Is there a way I could accomplish this?
Code this far:
priority_queue<Node*, vector<Node*>, node_comparison> minHeap;
And then I have a struct to compare the node's weights
struct node_comparison
{
bool operator<( const Node* a, const Node* b ) const
{
return a->totalWeight < b->totalWeight;
}
};
However it says there are too many parameters for this operator function. I've been trying to figure out how I could manage a min heap priority queue with my nodes for a while now and keep getting stuck. Any ideas?
If I understand your question correctly, I believe what you actually want is to make node_comparison a functor (more specifically, a binary predicate):
struct node_comparison
{
bool operator () ( const Node* a, const Node* b ) const
{
return a->totalWeight < b->totalWeight;
}
};
A functor is a class whose objects provide an overload of the call operator (operator ()) and, therefore, can be invoked with the same syntax you would use for invoking a function:
Node* p1 = ...;
Node* p2 = ...;
node_comparison comp;
bool res = comp(p1, p2) // <== Invokes your overload of operator ()
Internally, std::priority_queue will instantiate your predicate more or less like I did in the code snippet above, and invoke it that way to perform comparisons between its elements.
The advantage of functors over regular functions is that they could hold state information (something you probably won't need for the moment, but which often turns out to be desirable):
#include <cmath>
struct my_comparator
{
my_comparator(int x) : _x(x) { }
bool operator () (int n, int m) const
{
return abs(n - _x) < abs(m - _x);
}
int _x;
};
The above predicate, for instance, compares integers based on how distant they are from another integer provided at construction time. This is how it could be used:
#include <queue>
#include <iostream>
void foo(int pivot)
{
my_comparator mc(pivot);
std::priority_queue<int, std::deque<int>, my_comparator> pq(mc);
pq.push(9);
pq.push(2);
pq.push(17);
while (!pq.empty())
{
std::cout << pq.top();
pq.pop();
}
}
int main()
{
foo(7);
std::cout << std::endl;
foo(10);
}
You would need your comparison functor to implement bool operator()(....), not bool operator<(....):
struct node_comparison
{
bool operator()( const Node* a, const Node* b ) const
{
return a->totalWeight < b->totalWeight;
}
};