Create comparator for inserting triplets in min priority queue - c++

I have made a triplet using a class with all members as integers. I want to insert the triplet in min priority queue using STL in C++. I heard that it can be done using a bool comparator function, but don't have any idea about how to use it with 3 elements.
Note: I don't want to use vector pairs for inserting 3 values (I know how to do it ), I only want to use class triplets.
Can someone help me in implementing it?
using namespace std;
#include<bits/stdc++.h>
class triplet{
public:
int element;
int arrIndex;
int elementIndex;
};
priority_queue<triplet, vector<triplet>, greater<triplet>> pq;

I don`t know why you did std::vector, std::greater but.
#include <queue>
#include <vector>
class triplet {
public:
int element;
int arrIndex;
int elementIndex;
constexpr bool operator>(const triplet& r)
{
return element > r.element;
}
};
int main()
{
std::priority_queue<triplet, std::vector<triplet>, std::greater<>> queue;
triplet a, b;
a.element = 3;
b.element = 5;
queue.push(a);
queue.push(b);
}
This is possible by define a triplet operator.
or
#include <queue>
#include <vector>
class triplet {
public:
int element;
int arrIndex;
int elementIndex;
};
template <>
struct std::greater<triplet>
{
bool operator()(const triplet& l, const triplet& r)
{
return l.element > r.element;
}
};
int main()
{
std::priority_queue<triplet, std::vector<triplet>, std::greater<triplet>> queue;
triplet a, b;
a.element = 3;
b.element = 5;
queue.push(a);
queue.push(b);
}
through template specialization.

Related

Error when inserting vector of objects into set of vectors of objects

I would like to populate a set with a vector of tile objects, but I get an error.
#include <set>
#include <vector>
using namespace std;
struct tile
{
int value;
int suit;
};
tile makeTile(const int &a, const int &b)
{
tile t{a, b};
return t;
}
int main()
{
set<vector<tile>> s;
vector<tile> v;
v.push_back(makeTile(0, 0));
s.insert(v); // Error
return 0;
}
I don't get an error if I use integers rather than objects.
#include <set>
#include <vector>
using namespace std;
int main()
{
set<vector<int>> s;
vector<int> v;
v.push_back(0);
s.insert(v); // No error
return 0;
}
you can't make a set(actually ordered) of objects where logical operation is not possible.
But definitely you can make set by defining the logical operation by yourself. In programming sense, you can make set after doing some operator overloading.
Actually set is ordered set so you need to overload < operator for your struct.
Here is the code segment;
#include <iostream>
using namespace std;
struct tile{
int value;
int suit;
bool operator<(const tile& a);
};
tile makeTile(const int &a, const int &b)
{
tile t{a,b};
return t;
}
bool operator<(const tile& a, const tile& b){
return a.value <= b.value;
}
int main()
{
set<vector<tile> > s;
vector<tile> v;
v.push_back(makeTile(0,0));
v.push_back(makeTile(0,5));
v.push_back(makeTile(-1,5));
s.insert(v); // No Error here
}
if you want to check it then you can check it by following code:
for(auto &i:s){
for(auto &b:i){
cout << b.value << " " << b.suit << endl;
}
}
hope it will help.

How to copy elements from std::list to an array of struct?

I need to copy the contents of a std::list into an array, wherein the array is struct of array. Below is the code implementation of it.
#include <iostream>
#include <string>
using namespace std;
typedef struct
{
int height;
int width;
int length;
}dimensions;
GetDimensions(list<std::string>, *int); // Function that copies the content of list to array passed as second parameter
int main()
{
dimensions cuboid[10];
int plane[10];
list<std::string> planeList = GetList();//Function that returns list of elements
list<std::string> dimensionList = GetList();
GetDimensions(planeList,&plane);//This is fine, as it is a simple array
GetDimensions(dimensionList,&cuboid.height);//Trouble in implementation of this usecase, for cuboid.height, cuboid.width and cuboid.height.
return 0;
}
GetDimensions(list<std::string>dimensionList, int* dimensionParams)
{
int i=0;
for(list<std::string>::iterator it = dimensionList.begin(); it != dimensionList.end(); ++it)
{
dimensionParams[i] = stoi(*it);
i++;
}
}
Here, I need GetDimensions() function to copy the list (passed as first parameter) to array (second parameter). The implemented function works well for simple array plane. But how to pass the array of struct as parameter to the function ?
I will be getting the std::list as cuboid.height, cuboid.width and cuboid.length. So the function has to copy the contents of list from cuboid[0].height to cuboid[i].height respectively. Is there any specific function to copy the content directly?
Use std::array 's instead. Then your problem can be reduced to passing two different types of arrays to a single function.
This can be solved
either by good old function overloads
or in c++17 function template with
if-constexpr.
Following is an example code with templated function with if-constexpr (See live online)
#include <iostream>
#include <string>
#include <list>
#include <array>
#include <type_traits> // std::is_same_v
struct dimensions // no need to typedef here
{
int height;
int width;
int length;
};
template<typename T>
void GetDimensions(const list<std::string>& dimensionList, T& dimensionParams)
^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //---> pass list by const-ref as the values are non-modifying
{
int i{0};
if constexpr (std::is_same_v<std::array<int, 10>, T>)
{
for(const std::string& str: dimensionList) dimensionParams[i++] = std::stoi(str);
}
else
{
for(const std::string& str: dimensionList) dimensionParams[i++].height = std::stoi(str);
}
}
int main()
{
std::array<dimensions, 10> cuboid; // use std::array instead of VLA
std::array<int, 10> plane;
std::list<std::string> planeList{"1", "2"}; // some list
std::list<std::string> dimensionList{"1", "2"};
GetDimensions(planeList, plane);
GetDimensions(dimensionList, cuboid);
return 0;
}
Also note that:
You have not specified the return type of GetDimensions function.
You probably want to return void there.
in C++ you do not need to use typedef alias for struct { ... }.
last but not least, do not practice with using namespace std;
You can do this with boost::transform_iterator.
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
struct dimensions {
int height;
int width;
int length;
};
template <typename OutputIt>
void GetDimensions(std::list<std::string> dimensionList, OutputIt dimensionParams)
{
// N.b. taking the address of a standard library function is undefined, so wrap in a lambda
auto stoi = [](std::string s){ return std::stoi(s); };
std::copy(boost::make_transform_iterator(dimensionList.begin(), stoi),
boost::make_transform_iterator(dimensionList.end(), stoi),
dimensionParams);
}
int main() {
dimensions cuboid[10];
int plane[10];
std::list<std::string> planeList = GetList();
std::list<std::string> heightList = GetList();
std::list<std::string> widthList = GetList();
std::list<std::string> lengthList = GetList();
GetDimensions(planeList, plane);
GetDimensions(heightList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::height)));
GetDimensions(widthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::width)));
GetDimensions(lengthList,
boost::make_transform_iterator(cuboid, std::mem_fn(&dimensions::length)));
return 0;
}

how to use vector and struct members in method

im new in c++ (and not to old in programming...) and i have problem with handling vectors and strucs in class.
basically i have a vector and a array of pointers to struct members in the class and i want work on the in my methos but im doing something worng/
here is my movement.h
#pragma once
using namespace std;
class movement
{
private:
static const int MAX_ROW_PER_TRACKER = 100;
static const int MIN_TO_START_CALC = 30;
static const int MAX_TRACKERS = 20;
struct tracker
{
int id;
double a[MAX_ROW_PER_TRACKER];
double b[MAX_ROW_PER_TRACKER];
double c;
};
vector<int> trackersOrder[MAX_TRACKERS] = {};
tracker* trackersArr[MAX_TRACKERS];
public:
movement();
void addRow(int a, int b, int c);
~movement();
};
and my movement.cpp
#include "stdafx.h"
#include "movement.h"
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
movement::movement()
{
}
void movement::addRow(int id, int a, int b)
{
int index;
vector<int>::iterator searchID = find(trackersOrder.begin(), trackersOrder.end(), ID);
if (searchID == trackersOrder.end())
{
vector<int>::iterator freeLocation = find(trackersOrder.begin(), trackersOrder.end(), 0);
index = freeLocation - trackersOrder.begin();
trackersOrder.insert(trackersOrder.begin + index, id);
structArr[index] = new tracker;
structArr[index]->id = id;
structArr[index]->a[0] = a;
structArr[index]->b[0] = b;
structArr[index]->c = 0;
}
}
movement::~movement()
{
}
so when i send to method "addRow" id, and b i want to first check if i allready have this id in my vector (the vector just give me the index for the structs array) and if not then if put the id in the first empty place in the vector and on the structs array/
but from some reasin its look to me that the methid dont reconized the vector and the structs. can you help me understand why?
p.s - i can bet that i have more mistakes in my code, its my firs try with pointers and ect. (im comming from the good life in Matlab) so i will be happy to learn on them also
thank you very much!
The main problem
The problem is that in your code, trackersOrder is not a vector but an array of vectors:
vector<int> trackersOrder[MAX_TRACKERS] = {}; // array of MAXTRACKERS vectors !!
The solution
If you define it as simple vector, it should work better:
vector<int> trackersOrder;
If you want to set its size do it in the movement constructor:
movement::movement() : trackersOrder(MAX_TRACKERS)
{
}
Other issues
There is a case typo with an ID that should be id.
auto searchID = find(trackersOrder.begin(), trackersOrder.end(), id); // by the way auto is easier + ID corrected
There are a missing () after a begin whicn transforms unfortunately your iterator arithmetic into function pointer arithmetic (sic!!):
trackersOrder.insert(trackersOrder.begin() + index, id); // corrected
Finally, there are a couple of structArr that should be replaced by trackersArr.
The result does finally compile (online demo)

Custom priority queue comparator that accesses private members of a class

If you look at the code below, I am trying to create a priority_queue, I have named it DijkstraPriorityQueue, that has a custom comparator which also uses the private vector distTo.
You can see that I have some dots ....... as everything I tried have failed.
What is the cleanest solution (or possible solutions) to make this work as intended in this specific case ?
Dijkstra.h
class Dijkstra
{
public:
Dijkstra(Graph G, int s); // Create
~Dijkstra(); // Destroy
private:
bool compare(int u, int v)
{
return distTo[u] < distTo[v];
}
typedef priority_queue<int, vector<int>, .........> DijkstraPriorityQueue;
vector<float> distTo; // distTo[u] is the distance of the shortest s->u path
DijkstraPriorityQueue PQ; // Min-Priority Queue, implemented for Dijkstra
};
Dijkstra.cpp
Dijkstra::Dijkstra(Graph G, int s)
{
PQ = DijkstraPriorityQueue(...........);
}
Option #1
#include <functional>
#include <queue>
#include <vector>
class Dijkstra
{
public:
Dijkstra()
: PQ([this](int u, int v){ return distTo[u] < distTo[v]; })
{
}
private:
using DijkstraPriorityQueue
= std::priority_queue<int, std::vector<int>, std::function<bool(int,int)>>;
std::vector<float> distTo;
DijkstraPriorityQueue PQ;
};
Option #2
#include <functional>
#include <queue>
#include <vector>
class Dijkstra
{
public:
Dijkstra()
: PQ(std::bind(&Dijkstra::compare, this, std::placeholders::_1, std::placeholders::_2))
// or
// : PQ([this](int u, int v){ return compare(u, v); })
{
}
private:
bool compare(int u, int v) const
{
return distTo[u] < distTo[v];
}
using DijkstraPriorityQueue
= std::priority_queue<int, std::vector<int>, std::function<bool(int,int)>>;
std::vector<float> distTo;
DijkstraPriorityQueue PQ;
};
Option #3
(For the record, if you are stuck with C++03):
#include <queue>
#include <vector>
class Dijkstra
{
public:
Dijkstra()
: PQ(compare(this))
{
}
private:
struct compare
{
explicit compare(Dijkstra* d) : d(d) {}
bool operator()(int u, int v) const
{
return d->distTo[u] < d->distTo[v];
}
const Dijkstra* d;
};
typedef std::priority_queue<int, std::vector<int>, compare> DijkstraPriorityQueue;
std::vector<float> distTo;
DijkstraPriorityQueue PQ;
};

correct syntax for merge

This question might appear to be very stupid but I don't understand how to merge two sorted vectors with std::merge.
I tried some code using cplusplus reference.
struct t
{
t(int x):a(x){}
int a;
};
bool operator<(const t& p,const t&b)
{
return p.a<b.a;
}
int main()
{
vector<t> a,b,c;
a.push_back(t(10));
a.push_back(t(20));
a.push_back(t(30));
b.push_back(t(1));
b.push_back(t(50));
merge(a.begin(),a.end(),b.begin(),b.end(),c.begin());
return 0;
}
There is a segmentation fault with this code.
You will want to make sure c is big enough, or grows:
std::merge(a.begin(),a.end(),b.begin(),b.end(),std::back_inserter(c));
Alternatively:
c.resize(a.size() + b.size());
std::merge(a.begin(),a.end(),b.begin(),b.end(),c.begin());
See it Live On Coliru
#include <algorithm>
#include <vector>
#include <iterator>
struct t
{
t(int x):a(x){}
int a;
};
bool operator<(const t& p,const t&b)
{
return p.a<b.a;
}
int main()
{
std::vector<t> a,b,c;
a.push_back(t(10));
a.push_back(t(20));
a.push_back(t(30));
b.push_back(t(1));
b.push_back(t(50));
std::merge(a.begin(),a.end(),b.begin(),b.end(),std::back_inserter(c));
return 0;
}