How to get an index number by struct id in vector - c++

struct person{
int p_id;
};
std::vector<person> people;
person tmp_person;
tmp_person.p_id = 1;
people.push_back(tmp_person);
person tmp_person2;
tmp_person2.p_id = 2;
people.push_back(tmp_person2);
person tmp_person3;
tmp_person3.p_id = 3;
people.push_back(tmp_person3);
How can I find a index number of vector people by the person's id.
For example, how can I get a index number of a person who has p_id 2?

Use std::find_if to find the element. This returns an iterator to the element. And if you really want to know the index use std:distance:
int id_to_find = 1;
std:size_t found_idx = std::distance(
std::begin(people),
std::find_if(std::begin(people), std::end(people),
[=] (const person& p) { return p.p_id == id_to_find; })
);
But you should really use iterators in C++ unless you have a good reason to want indexes.

Search in the vector using for loop.
for(int i=0;i<people.size();i++){
if(people[i].p_id == 2){
return i
break;
}
}

Solution using find_if
#include <iostream> // std::cout
#include <algorithm> // std::find_if
#include <vector> // std::vector
int val=2;
struct person{
int p_id;
};
bool isValue (struct person i) {
return ((i.p_id)==val);
}
int main () {
std::vector<struct person> people;
person tmp_person;
tmp_person.p_id = 1;
people.push_back(tmp_person);
person tmp_person2;
tmp_person2.p_id = 2;
people.push_back(tmp_person2);
person tmp_person3;
tmp_person3.p_id = 3;
people.push_back(tmp_person3);
std::vector<person>::iterator it = std::find_if (people.begin(), people.end(), isValue);
std::cout << "The index of value is " << it-people.begin() << '\n';
return 0;
}

Related

passing std::list from one function to another by value

I have a C++ program as given below. I am trying to pass a std::list from one function to another by value. I expect the list to be accessible in the caller function by means of an iterator? I expect that the return will call the copy constructor of std::list and it will be accessible in the caller. Is my assumption wrong ? If not why am I getting a segmentation fault.
#include <list>
#include <map>
#include <string>
#include <set>
#include <iterator>
#include <iostream>
const char *sy_path = "/var/log";
struct Setting
{
typedef std::list<const Setting*> List;
const char* path;
const char* filename;
const char* name;
int def;
int min;
int max;
struct Original
{
const char* filename;
const char* name;
Original(const char* filename_, const char* name_)
:filename(filename_), name(name_)
{
}
}original;
static const List settings();
};
const Setting::List Setting::settings()
{
const Setting c_settings[] =
{ //default min max
{ sy_path, "cs.cfg", "num_a", 1, 1, 29, Original("sys.cfg", "num_a") }
,{ sy_path, "cs.cfg", "num_b", 1, 1, 6, Original("sys.cfg", "num_b") }
,{ sy_path, "cs.cfg", "num_c", 1, 1, 29, Original("sys.cfg", "num_c") }
};
Setting::List lst;
int numelem = sizeof(c_settings) / sizeof(Setting);
for (int i = 0; i < numelem; i++)
{
const Setting & tmpSetting = c_settings[i];
lst.push_back(&tmpSetting);
}
return lst;
}
static int get_settings(void)
{
Setting::List lst;
lst = Setting::settings();
for (Setting::List::const_iterator it = lst.begin() ; it != lst.end(); ++it)
{
const Setting *cs = *it;
std::cout << "path: " <<cs->path << "filename: " <<cs->filename << "name: " << cs->name << std::endl;
}
}
int main()
{
get_settings();
return 0;
}
Yes, return lst; will return a copy of lst. The problem is that you put in lst pointers to data located on the stack (const Setting c_settings[] variable). These pointers become invalid once you return from function, hence the segmentation fault. The solution is to either allocate memory for your settings on heap, or use a std::list<Setting>.
typedef std::list<Setting> List;
lst.push_back(c_settings[i]); // make sure you have the right copy constructor
or
lst.push_back(new Setting(c_settings[i])); // make sure you have the right copy constructor
Also, I would avoid usage of const char * and use std::string instead.

getting error on vector<unique_ptr<X>> v

I´m quiet new on C++ and currently learning to understand smart pointers.Therefore I`m currently working on a little console-program for inserting,searching and deleting songs ... for learning purposes to get used to the stuff =)
Here is my code:
Song.hpp
#pragma once
#include <vector>
#include <memory>
#include <string>
class Song
{
public:
typedef std::unique_ptr<Song> pSong;
public:
Song();
~Song();
void setTitle(std::string title);
void setArtist(std::string artist);
void checkSong(std::string item, int iterator);
void get();
private:
std::string _title;
std::string _artist;
};
Song.cpp
#include "Song.hpp"
#include <iostream>
Song::Song()
{
}
Song::~Song()
{
}
void Song::setTitle(std::string title)
{
_title = title;
}
void Song::setArtist(std::string artist)
{
_artist = artist;
}
void Song::checkSong(std::string item, int iterator)
{
if (_artist == item || _title == item)
{
std::cout << "Item found on Slot: " << iterator << std::endl;
}
else
{
std::cout << "No item found!" << std::endl;
}
}
void Song::get()
{
std::cout << _artist << " - " << _title << std::endl;
}
Main.cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>
#include "Song.hpp"
//prototype
void IntVector();
void SongVector();
Song* setSong(std::string title, std::string artist);
void find(std::string item, std::vector<Song::pSong> v);
std::vector<Song::pSong> SongList;
int main()
{
int k;
SongVector();
std::cin >> k;
return 0;
}
void IntVector()
{
// Create Vector
std::vector<std::unique_ptr<int>> v;
// Create a few unique_ptr<int> instances and fill them with ints
v.push_back(std::unique_ptr<int>(new int(30)));
v.push_back(std::unique_ptr<int>(new int(600)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(20)));
v.push_back(std::unique_ptr<int>(new int(200)));
v.push_back(std::unique_ptr<int>(new int(160)));
v.push_back(std::unique_ptr<int>(new int(4)));
v.push_back(std::unique_ptr<int>(new int(5)));
v.push_back(std::unique_ptr<int>(new int(315)));
// define vector<int> for storing values of the unique_ptr
std::vector<int> intList;
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
// Sort int of new Vector
std::sort(intList.begin(), intList.end());
// Loop through intList and cout
for (int i = 0; i < intList.size(); i++)
{
std::cout << intList[i] << std::endl;
}
}
void SongVector()
{
Song* first = setSong("Afroki","Steve Aoki");
Song* secound = setSong("Hype", "Steve Aoki");
Song* third = setSong("Madness", "Steve Aoki");
Song* fourth = setSong("Cake Face", "Steve Aoki");
SongList.push_back(Song::pSong(first));
SongList.push_back(Song::pSong(secound));
SongList.push_back(Song::pSong(third));
SongList.push_back(Song::pSong(fourth));
for (const auto& song : SongList)
{
song->get();
}
find("Madness", SongList);
}
Song* setSong(std::string title, std::string artist)
{
Song* song = nullptr;
song = new Song;
song->setArtist(artist);
song->setTitle(title);
return song;
}
void find(std::string item, std::vector<Song::pSong> v)
{
int i = 0;
for (const auto& song : v)
{
song->checkSong(item,i);
i++;
}
}
I got following error:
std::unique_ptr<Song,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
1> with
1> [
1> _Ty=Song
1> ]
I found out, that this error only occurs, when calling my find(...)-method, so I´m guessing that somewhere in there is my mistake, but I just cant find out, what Ive done wrong. Would appreciate your help.
std::unique_ptr provide unique ownership (hense the name) which means beside other you cannot copy instance of std::unique_ptr - which would mean shared ownership. When you passing std::vector<std::unique_ptr<whatever>> by value you creating a copy of vector instance, which tries to copy each element. So simplest solution would be to pass std::vector instance by const reference (as you do not have intention to modify vector):
void find( const std::string &item, const std::vector<Song::pSong>& v);
beside fixing your problem passing by (const) reference is more efficient for non trivial objects, so you can also use it for std::string
in your intVector() function:
for (int i = 0; i < v.size(); i++)
{
// get memory-adress of each element
auto result = v[i].get();
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
you do not really need to get raw pointer, just use std::unique_ptr itself:
for (int i = 0; i < v.size(); i++)
{
// get smart pointer for each element
const auto &result = v[i];
// store value of result-pointer in Vector
intList.push_back(*result);
std::cout << *result << std::endl;
}
void find(std::string item, std::vector<Song::pSong> v)
You need to pass vectors by reference. Add &.
void find(std::string item, std::vector<Song::pSong>& v)
Don't forget to also change the prototype of the function.

C++ Indexing structs

I'm wondering if there is a way to index structs in order to run through the member variables in a for-loop. I'm asking repeatingly for stuff and get input via cin>>:
struct Fruits {
string name;
int weight, diameter, prize;
string colour, smell, taste;
}apple;
cout << "Apple Name?"; cin >> apple.name;
cout << "Apple weight?"; cin >> apple.weight;
.
.
you get the idea. I want sth like
vector<string> questions {"Apple Name?", "Apple weight?", ... };
for (int j = 0; j < "StructureSize of Fruits"; j++)
{
cout << questions[j]; cin >> apple.j; //apple.j is the key point I want to know
}
thank you very much!
you can't.
Arrays access works on the following way.
int A[4];
A[0] = 5;
A[1] = 7;
A[3] = 8;
You know a int (in some archytectures) use 4 bytes. So, the first element of A is in the address A, the next element of A is in the address A+4 what is equal to say A+sizeof(int)
When you do the first assignment A[0] the code is really something like A+sizeof(int)*0, in the next A[1] is something like A+sizeof(int)*1 If you see, any adjacent space of the array sums 4 bytes ( or sizeof(int) ) and goes on. If you see, you know that A have integers inside of it and you know the pattern to access each element the general pattern in a for loop would be A+sizeof(int)*j in your struct you don't know what is inside, you can't do A+sizeof(X)*j becouse X isn't fixed, so, if you want to do that you must implement it yourself, but It would be a pain becouse you have mixed datatypes.
If your struct is fixed, the strings for the user should also be fixed, then why you try to print them from a loop?, The vector need to allocate and that use spaces and gpu, I think is better if you just print each option and then read the user input.
You can.
But not without overkilling it.
#include <string>
#include <iostream>
#include <memory>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/for_each.hpp>
struct Fruit {
std::string name;
int weight, diameter, price;
std::string colour, smell, taste;
};
BOOST_FUSION_ADAPT_STRUCT(
Fruit,
(std::string, name)
(int, weight)
(int, diameter)
(int, price)
(std::string, colour)
(std::string, smell)
(std::string, taste)
)
std::array<char const *const, 7> questions = {
"Name ?",
"Weight ?",
"Diameter ?",
"Price ?",
"Colour ?",
"Smell ?",
"Taste ?"
};
int main() {
Fruit apple;
auto input = [i = std::size_t{0u}](auto &field) mutable {
do {
std::cout << questions[i] << ' ';
} while(!(std::cin >> field));
++i;
};
boost::fusion::for_each(apple, std::ref(input));
std::cout << "----------\n";
auto output = [i = std::size_t{0u}](auto const &field) mutable {
std::cout << questions[i] << ' ' << field << '\n';
++i;
};
boost::fusion::for_each(apple, std::ref(output));
}
I just learned that boost::fusion::for_each can't accept a mutable functor, hence the weird and a bit dangerous use of std::ref()... It's a shame, really.
Output :
Name ? Apple
Weight ? 150
Diameter ? 8
Price ? 1
Colour ? red
Smell ? good
Taste ? sweet
----------
Name ? Apple
Weight ? 150
Diameter ? 8
Price ? 1
Colour ? red
Smell ? good
Taste ? sweet
enum FruitValueProperty { weight=0, diameter, prize, lastValueProperty };
enum FruitStringProperty { name=0, colour, smell, taste, lastStringProperty };
struct Fruit {
int ValueProperty[3];
string StringProperty[4];
int Weight() { return ValueProperty[weight]; }
int Diameter() { return ValueProperty[diameter]; }
int Prize() { return ValueProperty[prize]; }
string Name() { return StringProperty[name]; }
string Colour() { return StringProperty[colour]; }
string Smell() { return StringProperty[smell]; }
string Taste () { return StringProperty[taste ]; }
};
Fruit fruit;
vector<string> questions {"Fruit weight?", ... "Fruit name?", ... };
for (int i=0; i<lastValueProperty; i++) {
cout << questions[j];
cin >> fruit.ValueProperty[i];
}
for (int j=0; i<lastStringProperty; i++) {
cout << questions[lastValueProperty+j];
cin >> fruit.StringProperty[j];
}
int dim = fruit.Diameter();
string sm = fruit.Smell();
If you used enums for the string properties (limiting the scope of what the values could be i.e an enum for names, enum for colors etc) then you could get your result by condensing the two loops down to one.
Alternatively you could have set property for the int values that takes a string and parses it to int and go that route but I honestly thing the above is the simplest and clearest means to almost achieve what you want.
This is my take on the matter using just vanilla c++ and evil macros and casts. Still definitely overkill though.
The basic plan is to provide an operator[] to return a variant-type proxy class which in turn handles the io streams.
This interface allows you the ability to expose the class members as you choose and in the order you want.
In order not to repeat myself and to avoid having the burden of keeping things in sync I declare the fields I want in a separate header and include the header twice but changing the macro between includes. If I now add a new field or remove one then I only have to change one place.
fruit_fields.h
//NO Header Guards desired since we want to include multiple times
DECLARE_FIELD(std::string, Fruit, name)
DECLARE_FIELD(int, Fruit, weight)
DECLARE_FIELD(int, Fruit, diameter)
DECLARE_FIELD(int, Fruit, prize)
DECLARE_FIELD(std::string, Fruit, colour)
DECLARE_FIELD(std::string, Fruit, smell)
DECLARE_FIELD(std::string, Fruit, taste)
Utility Classes
#include <iostream>
#include <string>
#include <assert.h>
#include <vector>
#include <array>
#include <typeinfo>
//TypeId info
namespace FieldType
{
static const size_t String = typeid(std::string).hash_code();
static const size_t Integer = typeid(int).hash_code();
};
/*
Field Proxy is a simple variant class
If you want to support more field types then more code is needed
*/
class FieldProxy
{
public:
FieldProxy(int* value)
: m_typeHash( typeid(int).hash_code() )
, m_intValue(value)
{}
FieldProxy(std::string* value)
: m_typeHash(typeid(std::string).hash_code())
, m_stringValue(value)
{}
operator int() const
{
assert(m_typeHash == typeid(int).hash_code());
return *m_intValue;
}
operator std::string() const
{
assert(m_typeHash == typeid(std::string).hash_code());
return *m_stringValue;
}
friend std::ostream& operator<<(std::ostream& os, const FieldProxy& field);
friend std::istream& operator>>(std::istream& os, FieldProxy& field);
private:
size_t m_typeHash;
union
{
int* m_intValue;
std::string* m_stringValue;
};
};
std::ostream& operator<<(std::ostream& os, const FieldProxy& field)
{
if (field.m_typeHash == FieldType::Integer)
{
os << *(field.m_intValue);
}
else if (field.m_typeHash == FieldType::String)
{
os << *(field.m_stringValue);
}
return os;
}
std::istream& operator>>(std::istream& is, FieldProxy& field)
{
if (field.m_typeHash == FieldType::Integer)
{
is >> *(field.m_intValue);
}
else if (field.m_typeHash == FieldType::String)
{
is >> *(field.m_stringValue);
}
return is;
}
//data to obtain pointer to given field
struct FieldInfo
{
size_t fieldType;
size_t offset;
};
Fruit Class
//The struct we actually care about
struct Fruit
{
public:
static size_t getNumberFields()
{
return m_numberFields;
}
FieldProxy operator[](size_t index);
private:
//First include just declares the class members as you might expect
// string name;
// int weight; etc
#define DECLARE_FIELD(t, c, f) t f;
#include "fruit_fields.h"
#undef DECLARE_FIELD
static FieldInfo m_fields[];
static const size_t m_numberFields;
};
//Work out where the fields are positioned in the class
FieldInfo Fruit::m_fields[] =
{
//second time around - define the macro to generate the data
//needed to build the FieldProxy
#define DECLARE_FIELD( t, c, f) {typeid(t).hash_code(), offsetof(c,f)},
#include "fruit_fields.h"
#undef DECLARE_FIELD
};
//calculate how many fields there are
const size_t Fruit::m_numberFields = sizeof(Fruit::m_fields) / sizeof(Fruit::m_fields[0]);
//Index to a FieldInfo object and use it to create a FieldProxy variant
FieldProxy Fruit::operator[](size_t index)
{
assert(index < m_numberFields);
auto& fieldInfo = m_fields[index];
if (fieldInfo.fieldType == FieldType::Integer)
{
return FieldProxy(reinterpret_cast<int*> (reinterpret_cast<char*>(this) + fieldInfo.offset));
}
else if (fieldInfo.fieldType == FieldType::String)
{
return FieldProxy(reinterpret_cast<std::string*> (reinterpret_cast<char*>(this) + fieldInfo.offset));
}
else
{
assert(false);
return FieldProxy((int*)nullptr);
}
}
Main
You can now index in to the fruit class quite simply:
int main()
{
Fruit apple;
std::array<std::string, 7> questions = {
"Name ?",
"Weight ?",
"Diameter ?",
"Price ?",
"Colour ?",
"Smell ?",
"Taste ?"
};
assert(questions.size() == Fruit::getNumberFields());
for (size_t index = 0; index < Fruit::getNumberFields(); ++index)
{
bool succeeded = false;
do {
std::cout << questions[index] << ' ';
if (!(std::cin >> apple[index]))
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
else
{
succeeded = true;
}
} while (!succeeded);
}
std::cout << "----------" << std::endl;
for (size_t index = 0; index < Fruit::getNumberFields(); ++index)
{
std::cout << questions[index] << ' ' << apple[index] << std::endl;
}
return 0;
}
OK it is long since the thread was started.
For indexing a Struct with values of same type I have written this code:
struct DataValues
{
int Value1;
int Value2;
int Value3;
int Value4;
int Value5;
int Value6;
int Value7;
int Value8;
// the operator
// return the reference to make it settable.
int& operator[](int n)
{
// the idea, get the pointer of the first element
// and treat it as an array
return (&Value1)[n];
}
};
usage:
int main()
{
DataValues values;
values.Value4 = 6;
values[1] = 3;
values[0] = sizeof(DataValues);
return 0;
}
The downside is that you have to check the input parameter to avoid accessing memory which does not belong to the struct.
Chears

Accessing element of an array of struct.

So I have an struct
struct car{
string ownerName;
float price;
int year;
};
and I declared an array of these structs
car *cars = new car[1000]
Each car has an index, for example, the car with index 0 has name John Smith.
So, my question is knowing the name of the owner how do I access the index of the car. I know that the other way i would write
cars[0].name,
to get the name, but how would i do it backwards?
Two possible ways come to my mind.
One is writing a function that finds index by name.
#include <string>
using namespace std;
car *find_by_name(car* cars, const string& name, int from, int to) {
car* car_ptr = NULL;
for(int i = from; i < to; i++) {
if (cars[i].ownerName == name) {
car_ptr = cars+i;
break;
}
}
return car_ptr;
}
As you may notice, this function is very expensive (O(n)).
The other one and the easiest one, in my opinion, is using Map or HashMap to do so.
#include <map>
#include <string>
#include <iostream>
using namespace std;
car set_new_val(map<string, car*>& my_map, const string& name, const float price, const int year) {
car* car_heap = new car();
car_heap->ownerName = name;
car_heap->price = price;
car_hep->year = year;
my_map.insert(pair<string, car*>(name, car_heap));
}
car* find_car_by_name(const map<string, car*>& my_map, const string& name) {
map<string, car*>::iterator it;
if ((it = my_map.find(name)) == my_map.end())
return NULL;
return it->second;
}
int main(int argc, char* argv[]) {
map<string, car*> my_cars_data;
set_new_val(my_cars_data, "James", 2233000.5, 2013);
set_new_val(my_cars_data, "Dave", 1222000.5, 2011);
set_new_val(my_cars_data, "Aaron", 1222000.75, 2012);
car* james_car = find_car_by_name(my_cars_data, "James");
cout << "Year " << james_car->year << endl;
car* null_car = find_car_by_name(my_cars_data, "Santa");
if (null_car == NULL)
cout << "No owner with the name Santa is recorded" << endl;
...
...
free_map(my_map);
return 0;
According to C++11, lookup for a key using Map takes O(lgn) (HashMap is O(1)), for more details read here . That's a big pro, if you handle mass of data (not to mention that it is easier to maintain).
If you use a sequential container (array, vector...) you have to search for the name. In an unsorted array a linear search is required.
// linear search
string name = "joe";
auto it = find_if(begin(cars), end(cars),
[&name](const car& c) { return c.ownerName == name; });
auto index = it - begin(cars);
If you have performance problems with this approach you could sort the array and use a binary search (preferable if your array of cars does not change) or use a associative container which gives you fast access to an element by key (map, multi_map, unordered_map...)
// binary search
struct {
bool operator()(const car& lh, const car& rh) { return lh.ownerName < rh.ownerName; };
bool operator()(const car& lh, const std::string& rh) { return lh.ownerName < rh; };
bool operator()(const std::string& lh, const car& rh) { return lh < rh.ownerName; };
} byName;
sort(begin(cars), end(cars), byName);
auto it2 = lower_bound(begin(cars), end(cars), name, byName);
if (it != end(cars) && it->ownerName == name)
{
auto index2 = it - begin(cars);
}

Priority queue for user-defined types

I have the below struct:
struct node {
float val;
int count;
}
I have several objects of this struct. Now, I want to insert these objects into a priority queue of STL such that the priority queue orders the items by count. Any idea on how to do so? Preferably a min-heap is preferred. I know how to do the above for primitive data types, not structs
Overload the < operator:
bool operator<(const node& a, const node& b) {
return a.count > b.count;
}
I have reversed the comparison to achieve min heap without passing extra arguments to the priority queue.
Now you use it like this:
priority_queue<node> pq;
...
Edit: take a look at this post which seems to be almost exact duplicate: STL Priority Queue on custom class
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Boxer{
public:
string name;
int strength;
};
struct Comp{
bool operator()(const Boxer& a, const Boxer& b){
return a.strength<b.strength;
}
};
int main(){
Boxer boxer[3];
boxer[0].name="uday", boxer[0].strength=23;
boxer[1].name="manoj", boxer[1].strength=33;
boxer[2].name="rajiv", boxer[2].strength=53;
priority_queue< Boxer, vector<Boxer>, Comp> pq;
pq.push(boxer[0]);
pq.push(boxer[1]);
pq.push(boxer[2]);
Boxer b = pq.top();
cout<<b.name;
//result is Rajiv
return 0;
}
Using greater as comparison function you can use priority queue as min heap,
#include <bits/stdc++.h>
using namespace std;
int main()
{
priority_queue<int,vector<int>,greater<int> >pq;
pq.push(1);
pq.push(2);
pq.push(3);
while(!pq.empty())
{
int r = pq.top();
pq.pop();
cout << r << " ";
}
return 0;
}
Inserting value by changing their sign (using minus (-) for positive number and using plus (+) for negative number we can use priority queue in reversed order.
int main()
{
priority_queue<int>pq2;
pq2.push(-1); //for +1
pq2.push(-2); //for +2
pq2.push(-3); //for +3
pq2.push(4); //for -4
while(!pq2.empty())
{
int r = pq2.top();
pq2.pop();
cout << -r << " ";
}
return 0;
}
For custom data types or classes we need a to tell priority queue a way of knowing on which order it will sort our data.
struct compare
{
bool operator()(const int & a, const int & b)
{
return a>b;
}
};
int main()
{
priority_queue<int,vector<int>,compare> pq;
pq.push(1);
pq.push(2);
pq.push(3);
while(!pq.empty())
{
int r = pq.top();
pq.pop();
cout << r << " ";
}
return 0;
}
For custom structure or class you can use priority_queue in any order. Suppose, we want to sort people in descending order according to their salary and if tie then according to their age.
struct people
{
int age,salary;
};
struct compare {
bool operator()(const people & a, const people & b)
{
if(a.salary==b.salary)
{
return a.age>b.age;
} else {
return a.salary>b.salary;
}
}
};
int main()
{
priority_queue<people,vector<people>,compare> pq;
people person1,person2,person3;
person1.salary=100;
person1.age = 50;
person2.salary=80;
person2.age = 40;
person3.salary = 100;
person3.age=40;
pq.push(person1);
pq.push(person2);
pq.push(person3);
while(!pq.empty())
{
people r = pq.top();
pq.pop();
cout << r.salary << " " << r.age << endl;
}
Same result can be obtained by operator overloading :
struct people
{
int age,salary;
bool operator< (const people & p) const
{
if(salary==p.salary)
{
return age>p.age;
} else {
return salary>p.salary;
}
}
};
In main function :
priority_queue<people> pq;
people person1,person2,person3;
person1.salary=100;
person1.age = 50;
person2.salary=80;
person2.age = 40;
person3.salary = 100;
person3.age=40;
pq.push(person1);
pq.push(person2);
pq.push(person3);
while(!pq.empty())
{
people r = pq.top();
pq.pop();
cout << r.salary << " " << r.age << endl;
}
You need to provide operator< for that struct. Something like:
bool operator<(node const& x, node const& y) {
return x.count < y.count;
}
Now you can use a priority queue from the standard library.
Since C++11, you can write
auto comparer = [](const auto& a, const auto& b) {
return a.priority < b.priority;
};
std::priority_queue<Item, std::vector<Item>, decltype(comparer)> queue(comparer);
We can define user defined comparator class:
Code Snippet :
#include<bits/stdc++.h>
using namespace std;
struct man
{
string name;
int priority;
};
class comparator
{
public:
bool operator()(const man& a, const man& b)
{
return a.priority<b.priority;
}
};
int main()
{
man arr[5];
priority_queue<man, vector<man>, comparator> pq;
for(int i=0; i<3; i++)
{
cin>>arr[i].name>>arr[i].priority;
pq.push(arr[i]);
}
while (!pq.empty())
{
cout<<pq.top().name<<" "<<pq.top().priority;
pq.pop();
cout<<endl;
}
return 0;
}
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
class Person
{
public:
string name;
int age;
Person(string str,int num)
{
name = str;
age = num;
}
};
// FUNCTOR
class compare
{
public:
bool operator()(Person a,Person b)
{
cout << "Comparing " << a.age << " with " << b.age << endl;
return a.age < b.age;
}
};
int main()
{
int n;
cin >> n;
priority_queue <Person, vector<Person> , compare> pq;
for(int i=1;i<=n;i++)
{
string name;
int x;
cin >> name;
cin >> x;
Person p(name,x);
pq.push(p);
}
int k = 3;
for(int i=0;i<k;i++)
{
Person p = pq.top();
pq.pop();
cout << p.name << " " << p.age << endl;
}
return 0;
}
Operator() is also commonly overloaded to implement functors or function object. For example we have a structure Person which have some default ways of searching and sorting a person by age but we want our customized ways with some other parameter like weight so we may use our own custom functor. Priority queue is one such container which accepts a functor so it knows how to sort the objects of custom data types. Each time a comparison has to be done, a object is instantiated of class compare, and it is passed two objects of person class for comparison.