STL priority_queue of pairs<int, struct> error - c++

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.

Related

How to use a functor instead of lambda function

I was trying to solve a problem from Leetcode.
Problem description:
Given a n x n matrix where each of the rows and columns are sorted in ascending order, find the kth smallest element in the matrix.
Note that it is the kth smallest element in the sorted order, not the kth distinct element.
I solved it like this:
class Solution {
public:
int kthSmallest(std::vector<std::vector<int>>& matrix, int k) {
auto comp_gt = [&matrix](std::pair<int ,int> a, std::pair<int ,int> b)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
};
m = matrix.size();
if (m == 0) return 0;
n = matrix[0].size();
if (n == 0) return 0;
std::priority_queue<std::pair<int, int>,
std::vector<std::pair<int, int>>,
decltype(comp_gt)> min_heap(comp_gt);
for (int j = 0; j < n; ++j)
{
min_heap.emplace(0, j);
}
for (int i = 0; i < k-1; ++i)
{
int r = min_heap.top().first;
int c = min_heap.top().second;
min_heap.pop();
if (r != m - 1)
{
min_heap.emplace(r+1, c);
}
}
return matrix[min_heap.top().first][min_heap.top().second];
}
private:
int m;
int n;
};
This code works. However, when I tried to replace the lambda function with a functor, I wrote the functor like this:
class comp_gt
{
bool operator () (std::pair<int, int> a, std::pair<int, int> b, std::vector<std::vector<int>>& matrix)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
}
};
then I realized I didn't know how to pass the matrix to a functor like [&matrix] in a lambda function.
Can anyone help?
You need to pass the reference in the constructor of the functor. Note that the below code is equivalent to your lambda, but with the mutable modifier.
class comp_gt
{
public:
using Matrix = std::vector<std::vector<int>>;
comp_gt(Matrix& matrix) : matrix{matrix}{}
bool operator () (std::pair<int, int> a, std::pair<int, int> b, std::vector<std::vector<int>>& matrix)
{
return matrix[a.first][a.second] > matrix[b.first][b.second];
}
private:
Matrix& matrix;
};
Then use it as:
comp_gt comp{matrix};
"How to use a functor instead of lambda function" - Create a class with operator() (that optionally captures variables). A lambda is nothing but syntactic sugar (an easier way) to write such a (functor) class.
This is done by passing it to the comparator's constructor:
class comp_gt
{
std::vector<std::vector<int>>& matrix;
comp_gt(std::vector<std::vector<int>>& matrix) : matrix{matrix} {}
Now, your existing operator() can use it normally.
Then, when you actually go about constructing the comparator, you just construct it normally and pass the appropriate parameter to the constructor. Let's say you wanted to use your comparator with std::sort:
comp_gt comparator{some_matrix};
std::sort(something.begin(), something.end(), comparator);
Using this comparator with std::priority_queue is analogous.

C2100 illegal indirection Comparator and Sets

I'm trying to sort sets by value rather than keys. I keep running into the illegal indirection issue. The error occurs everytime I try to insert through the LRU cache. I assumed the issue had to do with not using pointers so I converted a and b to pointers instead but it didn't work.
struct comp {
bool operator ()(const pair<int, int>& a, const pair<int, int>& b) {
return a.second < b.second;
}
};
typedef set<pair<int, int>, comp> S;
struct LRUCache {
S cache;
typedef S::iterator it;
int cap;
LRUCache(int capacity) {
cap = capacity;
}
int get(int key) {
}
void setC(int key, int value) {
cache.insert(key, value);
}
void initialize() {
vector<int> temp{ 5,20,35,20,83,17,5,1,0,239,242,42 };
for (int i = 0; i < temp.size(); i++) {
setC(i, temp[i]);
}
}
};
int main()
{
LRUCache test(5);
test.initialize();
test.setC(1, 5);
test.setC(12, 20);
return 0;
}
The issue is that your std::set consists of std::pair<int, int>, and you're not inserting that type into your set with this line:
cache.insert(key, value);
This calls the set::insert function that takes two parameters, and the compiler is trying to match the two int values you're passing with one of the overloads here that takes two parameters.
Instead what you want to do is call set::insert with a single parameter, namely the std::pair<int, int>.
Change the above line to this:
cache.insert({key, value});
or
cache.insert(std::make_pair(key, value));
Live Example
You could also have seen the issue more clearly if you used using or typedef for the std::pair.
typedef std::pair<int, int> IntPair;
typedef std::set<IntPair, comp> PairSet;
//...
PairSet cache;
//...
cache.insert(IntPair(key, value));
You know that you want to insert IntPair's into the set, thus the code above would have compiled with no issue.

Passing a function_pointer as a comparator in a stl make_heap c++

I'm developing this program to run Dijkstra's Algorithm with an heap implementation and I want it to be as versatile as it can be so I'm using function pointer in order to avoid code repetition. This is the error that it pops. I'm using the stl make_heap
"Type must use '.*' or '->*' to call pointer-to-member function in '__comp (...)', e.g. '(... ->* __comp) (...)' "heap.h C/C++ Problem
Here is Dijkstra's Algorithm:
void Graph::dijkstraAlg(Vertex* ini, Vertex* fin, void(Graph::*weight_filler)(void), bool(Graph::*pq_order)(const Vertex* &, const Vertex* &)){
for(unsigned int i = 0; i < vertexs.size(); i++) {
vertexs[i]->path = NULL;
vertexs[i]->holder = MAX_INT_VALUE;
vertexs[i]->processing=false;
}
(this->*weight_filler)();
Vertex* v=ini;
v->holder = 0;
v->processing = true;
vector<Vertex*> pq;
pq.push_back(v);
make_heap(pq.begin(),pq.end(),pq_order);
while(!pq.empty()){
v=pq.front();
pop_heap(pq.begin(),pq.end());
pq.pop_back();
for(unsigned int u=0; u < v->adj.size(); u++){
Vertex* w = v->adj[u]->dest;
if((v->holder+v->adj[u]->weight) < w->holder){
w->holder=v->holder + v->adj[u]->weight;
w->path=v;
if(!w->processing){
w->processing=true;
pq.push_back(w);
}
}
make_heap(pq.begin(),pq.end(),pq_order);
}
}
return;}
The error is in the make_heap and I can't figure it out, any help is appreciated.
Here is the function I'm passing to the make_heap:
bool Graph::regular_PqOrder(const Vertex* &v, const Vertex* &u){
return v->holder > u->holder;}
This is how I call the algo:
dijkstraAlg(i,f,&Graph::price_WeightFiller,&Graph::regular_PqOrder);
If you need more information just tell me and I edit it.
Thank you pal's
You're passing the wrong type. std::make_heap takes a functor as the third element, which should satisfy the requirements of Compare, which are that you need:
bool operator()(const Type1&, const Type2&) const;
You are passing in pq_order which is of type:
bool(Graph::*)(const Vertex* &, const Vertex* &)
That's a pointer-to-member, it's not callable without an object of type Graph. Hence the error about "Type must use '.' or '->' to call pointer-to-member". The simplest approach is to simply provide that object, which in your case is this:
using namespace std::placeholders;
std::make_heap(pq.begin(), pq.end(),
std::bind(pq_order, this, _1, _2));
Alternatively, since regular_PqOrder doesn't actually rely on any of the members of other methods of Graph, you could also just be to make it static:
class Graph {
public:
static bool regular_PqOrder(const Vertex* &v, const Vertex* &u)
{
return v->holder > u->holder;
}
};
And pass in Graph::regular_PqOrder now as a function pointer, rather than pointer-to-method.
I have simplified your problem to:
#include <algorithm>
#include <vector>
using namespace std;
class Vertex
{};
class Graph
{
public:
void dijkstraAlg(Vertex* ini, Vertex* fin, void(Graph::*weight_filler)(void),
bool(Graph::*pq_order)(const Vertex*, const Vertex*))
{
(this->*weight_filler)();
struct Comparator
{
private:
Graph* m_g;
bool(Graph::*m_fn)(const Vertex*, const Vertex*);
public:
Comparator(Graph* g, bool(Graph::*fn)(const Vertex*, const Vertex*)) : m_g(g), m_fn(fn)
{}
bool operator()(const Vertex* one, const Vertex* two) const
{
return (m_g->*m_fn)(one, two);
}
};
Comparator comparator(this, pq_order);
vector<Vertex*> pq;
std::make_heap(pq.begin(), pq.end(), comparator);
}
void weight_filler1()
{
}
bool pq_order1(const Vertex*, const Vertex*)
{
return false;
}
};
int main()
{
Graph g;
g.dijkstraAlg(nullptr, nullptr, &Graph::weight_filler1, &Graph::pq_order1);
return 0;
}
The problem is: std::make_heap expects a function pointer- in your case you are passing a pointer to member function thus the issue.
Either you can change the declaration of dijkstraAlg to take in just a static function pointer pq_order or wrap up pq_order in a structure to make it a callable entity in itself like I have done.
Note: you will have to fixup references to pointers in pq_order for make_heap to compile anyway

sort one array and other array following?

here is the C++ sample
int a[1000] = {3,1,5,4}
int b[1000] = {7,9,11,3}
how do i make it so if i sort array a, array b also following array a
example
a[1000] = {1,3,4,5}
b[1000] = {9,7,3,11}
is it possible using sort function
sort(a,a+4)
but also sort array b aswell ?
edit: what if there are 3 arrays ?
Instead of using two arrays, can you use an array of pairs and then sort THAT using a special comparison functor rather than the default less-than operator?
The simplest way is to rearrange your data into an array-of-structs instead of a pair of arrays so that each datum is contiguous; then, you can use an appropriate comparator. For example:
struct CompareFirst
{
bool operator() (const std::pair<int,int>& lhs, const std::pair<int,int>& rhs)
{
return lhs.first < rhs.first;
}
};
// c[i].first contains a[i], c[i].second contains b[i] for all i
std::pair<int, int> c[1000];
std::sort(c, c+1000, CompareFirst());
If you can't refactor your data like that, then you need to define a custom class that acts as a RandomAccessIterator:
struct ParallalArraySortHelper
{
ParallelArraySortHelper(int *first, int *second)
: a(first), b(second)
{
}
int& operator[] (int index) { return a[index]; }
int operator[] const (int index) { return a[index]; }
ParallelArraySortHelper operator += (int distance)
{
a += distance;
b += distance;
return *this;
}
// etc.
// Rest of the RandomAccessIterator requirements left as an exercise
int *a;
int *b;
};
...
int a[1000] = {...};
int b[1000] = {...};
std::sort(ParallalArraySortHelper(a, b), ParallelArraySortHelper(a+1000, b+1000));
Generate an array the same size as the original, containing the indexes into the array: {0, 1, 2, 3}. Now use a custom comparator functor that compares the elements in an associated array rather than the indexes themselves.
template<typename T>
class CompareIndices
{
public:
CompareIndices(const T * array) : m_AssociatedArray(array) {}
bool operator() (int left, int right) const
{
return std::less(m_AssociatedArray[left], m_AssociatedArray[right]);
}
private:
const T * m_AssociatedArray;
};
std::sort(i, i+4, CompareIndices(a));
Once you have a sorted list of indices, you can apply it to the original array a, or any other b array you want.

Can I use vector as index in map structure in c++?

I attempted to do something like this but it does not compile:
class point
{
public:
int x;
int y;
};
int main()
{
vector<point> vp1;
vector<point> vp2;
vector<point> vp3;
map < vector<point>, int > m;
m[vp1] = 1;
m[vp2] = 2;
m[vp3] = 3;
map < vector<point>, int >::iterator it;
for (it=m.begin(); it!=m.end(); it++)
{
cout<<m[it->first]<<endl;
}
return 0;
}
You can use anything as the index type into a std::map as long as it supports an operator< (which could could define as a free-standing function -- doesn't have to be a member function, as long as you can write a < b for a and b being instances of your type of interest) with the usual semantics (antireflexive, transitive, ...). Or, you can pass a binary function with the same semantics to use in lieu of <, if that suits you better.
You can, but the type used as a key in a map needs to be comparable, either using operator<, or using a comparison function/functor you supply as the third template parameter for the map type.
Yes, you can. Vectors, like all containers, are comparable. The resulting map will sort the vectors in lexicographic order.
The problem is that point is not comparable. You have to define a sort order for points, and then this will in turn define lexicographic order over vector<point>.
class point
{
public:
int x;
int y;
};
bool operator<( point const &l, point const &r ) {
return l.x < r.x? true
: r.x < l.x? false
: l.y < r.y;
}
A simpler solution is to use std::pair instead of defining your own point.
typedef pair< int, int > point; // point::first = x, point::second = y
// pair is already comparable; order defined as in previous example
typedef vector<point> pointvec; // OK
You haven't defined a function to compare a vector<point> Maps make requiremets of keys checking of equivalence and comparison.
You have to declare the operator<. It would look like this (please keep in mind, that the three vectors in your sample code actually look the same):
bool operator<(const vector<point>& left, const vector<point>& right)
{
return left.size() < right.size();
}