I am trying to implement kruskal's algo. togather with bfs and dfs. i wrote my code to print the adjancey list and to show the bfs and dfs and now i am facing problem with writing the code for kruskal's algorithm i kind of newbie in using maps and templates. i don't know how to pass the values in the kruskals algorithm and i m constantly getting errors.
here is the code that i have written.
#include<iostream>
#include<map>
#include<queue>
#include<list>
#include<cstring>
#include<algorithm>
using namespace std;
template<typename T>
class Graph{
private:
map<T,list<pair<T,int>>> l;
void DFSHelper(T node,map<T,bool> &visited){
cout<<node<<" -> ";
visited[node]=true;
for(auto neighbours:l[node]){
if(!visited[neighbours.first]){
DFSHelper(neighbours.first,visited);
}
}
}
public:
void add(T A,T B,bool bi,int wi){
l[A].push_back(make_pair(B,wi));
if(bi == true){
l[B].push_back(make_pair(A,wi));
}
}
void print(){
for(auto c:l){
int c1 = c.first;
list<pair<int,int>> n = c.second;
cout<<c1<<" -> ";
for(auto k:n){
int dest = k.first;
int dist = k.second;
cout<<dest<<"("<<dist<<") ";
}
cout<<endl;
}
}
void bfs(T src){
map<T,bool> visited;
queue<T> q;
q.push(src);
visited[src] = true;
while(!q.empty()){
T node = q.front();
q.pop();
cout<<node<<" -> ";
for(auto children:l[node]){
if(!visited[children.first]){
visited[children.first]=true;
q.push(children.first);
}
}
}
}
void dfs(T src){
map<T,bool> visited;
int component = 1;
DFSHelper(src,visited);
}
void cmp(T src,T end){
return src.second.second<end.second.second;
}
void kruskals(){
}
};
int main(){
Graph<int> g;
g.add(1,2,true,20);
g.add(1,3,true,30);
g.add(2,4,true,50);
g.add(3,4,true,10);
g.add(4,5,true,60);
g.add(5,1,false,35);
g.print();
cout<<endl;
cout<<"BFS :- ";
g.bfs(1);
cout<<endl;
cout<<"DFS :- ";
g.dfs(1);
g.kruskals();
}
Your graph appears to be directed due to the uni-directional edge 5->1. Kruskal's algorithm only works for undirected graphs. (Why?)
In Kruskal's algorithm you need the edges sorted in non-decreasing order of edge-weights. Hence you can either maintain an extra data structure alongwith the map l and insert to it in the add() function or create it in the kruskals() function itself.
Next you need a data structure to query if any two nodes of the graph belong to two different components or not. Here two nodes are said to be in the same component if you can reach one node to the other by only considering edges encountered till that particular iteration of the Kruskal's algorithm. A Disjoint Set Union can do that efficiently.
Here is an implementation, where I use the set edge_weights to store the edges sorted by weight:
#include<iostream>
#include<map>
#include<queue>
#include<list>
#include<cstring>
#include<algorithm>
#include <set> // Added
using namespace std;
template<typename T>
class DisjointSetUnion {
map<T, T> parent;
map<T, int> sz; // stores sizes of component
public:
void make_set(T v) {
parent[v] = v;
}
T find_set(T x) {
if(x != parent[x]) parent[x] = find_set(parent[x]);
return parent[x];
}
void merge_sets(T x, T y) {
int px = find_set(x), py = find_set(y);
if(sz[px] > sz[py]) parent[py] = px;
else parent[px] = py;
if(sz[py] == sz[px]) sz[py]++;
}
};
template<typename T>
class Graph{
private:
map<T,list<pair<T,int>>> l;
set<pair<int, pair<T, T>>> edge_weights; // no parallel (or duplicate) edges exist
void DFSHelper(T node,map<T,bool> &visited){
cout<<node<<" -> ";
visited[node]=true;
for(auto neighbours:l[node]){
if(!visited[neighbours.first]){
DFSHelper(neighbours.first,visited);
}
}
}
public:
void add(T A,T B,bool bi,int wi){
l[A].push_back(make_pair(B,wi));
if(bi == true){
l[B].push_back(make_pair(A,wi));
edge_weights.insert(make_pair(wi, make_pair(A, B))); // Added
}
}
void print(){
for(auto c:l){
int c1 = c.first;
list<pair<int,int>> n = c.second;
cout<<c1<<" -> ";
for(auto k:n){
int dest = k.first;
int dist = k.second;
cout<<dest<<"("<<dist<<") ";
}
cout<<endl;
}
}
void bfs(T src){
map<T,bool> visited;
queue<T> q;
q.push(src);
visited[src] = true;
while(!q.empty()){
T node = q.front();
q.pop();
cout<<node<<" -> ";
for(auto children:l[node]){
if(!visited[children.first]){
visited[children.first]=true;
q.push(children.first);
}
}
}
}
void dfs(T src){
map<T,bool> visited;
int component = 1;
DFSHelper(src,visited);
}
void cmp(T src,T end){
return src.second.second<end.second.second;
}
void kruskals(){
DisjointSetUnion<int> dsu;
// make singleton components of each node
for(auto it: l) {
T u = it.first;
dsu.make_set(u);
}
// iterate over all edges in sorted order
for(auto ed: edge_weights) {
int w = ed.first;
T u = ed.second.first, v = ed.second.second;
// if they belong to different components then they are
// part of the MST, otherwise they create a cycle
if(dsu.find_set(u) != dsu.find_set(v)) {
// this edge is part of the MST, do what you want to do with it!
cout << "(" << u << "," << v << "," << w << "), ";
// merge the two different components
dsu.merge_sets(u, v);
}
}
}
};
int main(){
Graph<int> g;
g.add(1,2,true,20);
g.add(1,3,true,30);
g.add(2,4,true,50);
g.add(3,4,true,10);
g.add(4,5,true,60);
// Removed unidirectional edge below
// g.add(5,1,false,35);
g.print();
cout<<endl;
cout<<"BFS :- ";
g.bfs(1);
cout<<endl;
cout<<"DFS :- ";
g.dfs(1);
cout << endl;
cout << "Edges in MST (u,v,w): ";
g.kruskals();
cout << endl;
}
Related
So I've been trying to implement Kruskal's algorithm, first I want to make clear the question is not related to the implementation of the algorithm. I've created one graph.hpp file, one kruskalsAlgo.hpp and main.cpp as follows respectively:
#pragma once
struct Edge
{
int source;
int destination;
int weight;
};
struct Graph
{
int V;
int E;
Edge* edge;
};
Graph* create_graph(int V, int E)
{
Graph* graph = new Graph;
graph -> V = V;
graph -> E = E;
graph -> edge = new Edge[E];
return graph;
}
#include <stdlib.h>
#include <tuple>
#include "../Graph/Graph.hpp"
class Kruskals_Algo
{
private:
struct subset
{
int parent;
int rank;
};
void make_set(subset*, int);
int find_set(subset*, int);
void _union(subset*, int, int);
public:
Edge* kruskal(Graph*);
void print_kruskals_MST(Edge*, int);
};
void Kruskals_Algo::make_set(subset* subsets, int V)
{
subsets[V].parent = V;
subsets[V].rank = 0;
}
int Kruskals_Algo::find_set(subset* subsets, int V)
{
if(subsets[V].parent != V)
subsets[V].parent = find_set(subsets, subsets[V].parent);
return subsets[V].parent;
}
void Kruskals_Algo::_union(subset* subsets, int x, int y)
{
int xroot = find_set(subsets, x);
int yroot = find_set(subsets, y);
if(subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if(subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
else
{
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}
inline int myComp(const void* a, const void* b)
{
Edge* a1 = (Edge*)a;
Edge* b1 = (Edge*)b;
return a1 -> weight > b1 -> weight;
}
Edge* Kruskals_Algo::kruskal(Graph* graph)
{
int V = graph -> V;
Edge result[V];
Edge* result_ptr = result;
int e = 0;
int i = 0;
qsort(graph -> edge, graph -> E, sizeof(graph -> edge[0]), myComp);
subset* subsets = new subset[(V * sizeof(subset))];
for (int v = 0; v < V; ++v)
make_set(subsets, v);
while(e < V - 1 && i < graph -> E)
{
Edge next_edge = graph -> edge[i++];
int x = find_set(subsets, next_edge.source);
int y = find_set(subsets, next_edge.destination);
if (x != y)
{
result[e++] = next_edge;
_union(subsets, x, y);
}
}
//return std::make_tuple(res, e);
return result_ptr;
}
void Kruskals_Algo::print_kruskals_MST(Edge* r, int e)
{
int minimumCost = 0;
for(int i=0; i<e; ++i)
{
std::cout << r[i].source << " -- "
<< r[i].destination << " == "
<< r[i].weight << std::endl;
minimumCost = minimumCost + r[i].weight;
}
std::cout << "Minimum Cost Spanning Tree: " << minimumCost << std::endl;
}
#include <iostream>
#include "Graph/Graph.hpp"
#include "Kruskals_Algo/kruskalsAlgo.hpp"
//#include "Prims_Algo/primsAlgo.hpp"
using namespace std;
class GreedyAlgos
{
public:
void kruskals_mst();
//void prims_mst();
};
void GreedyAlgos::kruskals_mst()
{
Kruskals_Algo kr;
int V;
int E;
int source, destination, weight;
cout << "\nEnter the number of vertices: ";
cin >> V;
cout << "\nEnter the number of edges: ";
cin >> E;
Edge* res;
Graph* graph = create_graph(V, E);
for(int i=0; i<E; i++)
{
cout << "\nEnter source, destinstion and weight: ";
cin >> source >> destination >> weight;
graph -> edge[i].source = source;
graph -> edge[i].destination = destination;
graph -> edge[i].weight = weight;
}
//std::tie(result, E) = kr.kruskal(graph);
res = kr.kruskal(graph);
kr.print_kruskals_MST(res, E);
}
int main()
{
int choice;
GreedyAlgos greedy;
greedy.kruskals_mst();
return 0;
}
So my question here is when I debug the program the values in Edge result[V], which is a structure array, are calculated correctly, at position [0] [1] [2] as in the following picture:
but when the function print_kruskals_MST(res, E) is called from the main the values printed are different:
Is there any pointer thing that I'm doing wrong?
Thanks in advance!
P.S. Ignore the comments!
This answer might not answer your question directly but it should shed some light on the problem.
First of all, yes you have a lot of pointer problems...
Secondly, pair ANY use of the new operator with the delete operator. As it stands, you have a bunch of memory leaks.
Also, why create_graph? Create a constructor for Graph instead (and a destructor since the class has an Edge* edge it needs to take care of).
struct Graph
{
int V;
int E;
Edge* edge;
// constructor
Graph(int V, int E)
{
this->V = V;
this->E = E;
this->edge = new Edge[E];
}
// destructor
~Graph()
{
// nullify the member variable before deleting its memory is just a safety measure pertaining to multithreading.
Edge* _edge = this->edge;
this->edge = nullptr;
delete _edge;
}
};
Then change Graph* graph = create_graph(V, E); into Graph* graph = new Graph(V, E); and do delete graph when you're done using it.
Make sure you remove all memory leaks and we can go on to discussing referencing the correct data (f.ex. by me changing my answer).
Can anybody explain me, how to do Breadth first search in the graph that uses vector of linked lists ?
My Graph header file:
#include <string>
#include <iostream>
#include <map>
#include <vector>
using namespace std;
struct vertex {
string code;
vertex* next;
};
struct AdjList {
vertex *head;
AdjList(vertex* Given) {
head = Given;
}
};
class Graph {
map<string, string> associations;
int nodeNum; //amount of nodes or size of the graph;
vector<AdjList> adjList;
public:
Graph(int NodeNum);
~Graph();
int singleSize(string codeName);
int getSize();// must destroy every prerequisite list connected to the node
vertex* generateVertex(string codeName);
int getIndexOfVertex(vertex* givenVertex); // will find the location of the vertex in the array
void addVertex(vertex* newVertex);
void addEdge(string codeName, string linkCodeName);
void printPrerequisites(vertex* ptr, int i);
bool deleteVertex(string codeName);
bool deleteEdge(string codeName, string linkCodeName);
bool elemExistsInGraph(string codeName);
void printPrereq(string codeName);
void printCourseTitle(string codeName);
void printGraph();
};
I am trying to print all connected nodes within the graph using the breadth first search. Here is my code for the breadth first search algorithm that does not work.
void Graph::printPrereq(string codeName) {
int adjListSize = this->adjList.size();
int index = getIndexOfVertex(generateVertex(codeName));
bool visited[this->adjList.size()];
for(int i = 0; i < adjListSize; i++) {
visited[i] = false;
}
list<int> queue;
visited[index] = true;
queue.push_back(index);
while(!queue.empty()) {
index = queue.front();
vertex* pointer = this->adjList[index].head;
cout << pointer->code;
queue.pop_front();
while(pointer != nullptr){
if(!visited[getIndexOfVertex(pointer)]) {
queue.push_back(getIndexOfVertex(pointer));
visited[getIndexOfVertex(pointer)] = true;
}
cout << pointer->code <<"->";
pointer = pointer->next;
}
cout << "Null" << endl;
}
}
This algorithm outputs nodes that are only within the linked list, but not the ones that are connected through the graph.
Can anybody help and solve this problem?
I am trying to create a program that takes N random nodes from user input and creates a random integer that is put into a binary tree and then copied into a priority queue. The integer becomes the key for each node and another integer counts the frequency of the key. I run into issues when I copy into the priority queue because I get duplicates and I need to remove them. I tried to create a set through the node constructor but I get the error above in the .cpp file.
#include <iostream>
#include <random>
#include <ctime>
#include <queue>
#include <set>
#include <functional>
#include <algorithm>
#include<list>
#include "Q7.h"
using namespace std;
int main()
{
node * root=NULL;
node z;
int n,v;
vector<int> first;
vector<int>::iterator fi;
default_random_engine gen(time(NULL));
cout<<"how many values? "; cin>>n;
for(int i=0; i<n; i++)
{ (v=gen()%n);
first.push_back(v);
if(root==NULL){root = node(set(v));}///This is where I get the error!!
else{
root->addnode(v);
}
}
z.unsortedRemoveDuplicates(first);
cout<<"Binary Tree in a depth first manner with Duplicates removed!"<<endl;
for ( fi = first.begin() ; fi != first.end(); ++fi{cout<<"Node "<<*fi<<endl;}
cout<<"-------------------"<<endl;
root->display();
cout<<"-------------------"<<endl;
cout<<"-------------------"<<endl;
root->display_Queue1();
cout<<"-------------------"<<endl;
return 0;
}
my .h file
class node
{
public:
node(){left=NULL; right=NULL; ct = 1;}
node set(int v) {val = v; left=NULL; right=NULL; ct=1;}
node (int Pri, int cat)
: val(Pri), ct(cat) {}
friend bool operator<(//sorts queue by lowest Priority
const node& x, const node& y) {
return x.val < y.val;
}
friend bool operator>(//sorts queue by greatest Priority
const node& x, const node& y) {
return x.ct > y.ct;
}
friend ostream&//prints out queue later
operator<<(ostream& os, const node& Pri) {
return os <<"my value = "<<Pri.val<<" occured "<<Pri.ct<<" times";
}
int unsortedRemoveDuplicates(vector<int>& numbers)
{
node set<int> seenNums; //log(n) existence check
auto itr = begin(numbers);
while(itr != end(numbers))
{
if(seenNums.find(*itr) != end(seenNums)) //seen? erase it
itr = numbers.erase(itr); //itr now points to next element
else
{
seenNums.insert(*itr);
itr++;
}
}
return seenNums.size();
}
priority_queue<node, vector<node>, greater<node> > pq;
priority_queue<node, vector<node>, less<node> > pq1;
void addnode(int v)
{
if(v==val){ct++;}
pq.emplace(node (set (v)));///No error here for set with constructor why??
pq.emplace(node (set (v)));
if(v<val)
{
if(left==NULL){left=new node(set(v));
}
else{left->addnode(v);
}
}
else
{
if(right==NULL){right = new node (set(v));
}
else{right->addnode(v);
}
}
}
int display()
{
if(left!=NULL){left->display();}
cout<<"frequency "<<ct<<" value"<<val<<endl;
if(right!=NULL){right->display();}
}
void display_Queue()
{
cout << "0. size: " << pq.size() << '\n';
cout << "Popping out elements from Pqueue..."<<'\n';
while (!pq.empty())
{
cout << pq.top() << endl;
pq.pop();
}
cout << '\n';
}
void display_Queue1()
{
cout << "0. size: " << pq1.size() << '\n';
cout << "Popping out elements from Pqueue..."<<'\n';
while (!pq1.empty())
{
cout << pq1.top() << endl;
pq1.pop();
}
cout << '\n';
}
private:
int val; ///value in that node
int ct;
///ct = count of that value
node * left;
node * right;
};
Congratulations, with this line:
root = node(set(v));
You have discovered why people here often say to avoid using using namespace std;. This is being interpreted as:
root = static_cast<node>(std::set(v));
Instead of what you want, which might be:
root = new node();
root->set(v);
First, note that we need to use new as we are creating a new node, not trying to cast a node to a node, which would have also given another compiler error about trying to assign a value to a pointer.
Next, note that you don't get the error in the header file as there is no using namespace std; there, and since it is in a member function, the line:
void node::addnode(int v)
{
//...
pq.emplace(node (set (v)));///No error here for set with constructor why??
//...
}
Is interpreted as:
pq.emplace(static_cast<node>(this->set(v)));
However, is this what you really want to do?
Furthermore, I would change the constructors to be:
public:
node (int Pri = 0, int cat = 1)
: val(Pri), ct(cat), left(NULL), right(NULL) {}
// DELETED node (int Pri, int cat)
Thus you can do:
root = new node(v);
And it will work as I think you expect it to.
I have already implemented an adjacency matrix graph which uses just integers types.(consider C++ for everything that I mention here)
I'm implementing another graph that will receive cities in the vertexes and distances in the edges using my old implementation. I was wondering if this is a good idea or I should use a different implementation for this problem like linked lists. The idea here is to read all the cities and their distances to each other from a txt file, add it in the graph and then display a menu to the user so he/she can consult the distance from city A to B and get a list of all the cities he needs to travel before they reach the target.
I'm planning to read the city, give it a number code, and add it in the graph, instead of adding the string "city" (would need to convert the graph from integer to string)
What do you think,any idea/advice?
You can use either map for that. Like this
map<pair<string,string>,int> city ;
(See implementation 2)
Or you can use vector to keep track of city names with their index(implementation 1)
Implementation 1
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
class Graph
{
int V; // start vertice
map<pair<string,string>,int> city ;
vector<string> city1;
vector<string> city2;
public:
Graph(int start_V)
{
V = start_V;
}
void addEdge(string start,string end,int wt);
void display();
};
void Graph::addEdge(string start,string end,int wt)
{
city[make_pair(start,end)] = wt;
}
void Graph::display()
{
int flag=0;
for(auto it:city)
{
city1.push_back(it.first.first);
city2.push_back(it.first.second);
}
sort(city1.begin(), city1.end());
auto last = unique(city1.begin(), city1.end());
city1.erase(last, city1.end());
sort(city2.begin(), city2.end());
auto last2 = unique(city2.begin(), city2.end());
city2.erase(last2, city2.end());
for(auto col:city2)
{
cout<<"\t"<<col;
}
cout<<"\n";
for(auto row:city1)
{
int flag =0; //for printing row for once
for(auto col:city2)
{
if (!flag)
cout<<row;
cout<<"\t"<<city[make_pair(row,col)];
flag = 1;
}
cout<<"\n";
}
}
int main()
{
Graph g(2);
g.addEdge("A","B",1);
g.addEdge("C","A",5);
g.addEdge("D","E",7);
g.addEdge("E","A",5);
g.addEdge("D","B",7);
g.addEdge("D","L",7);
g.addEdge("W","L",7);
g.display();
return 0;
}
Implementation 2
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
class Graph {
int V; // start vertice
map<pair<string,string>,int> city ;
vector<string> city1;
vector<string> city2;
public:
Graph(int start_V)
{
V = start_V;
}
void addEdge(string start,string end,int wt);
void display(); }; void Graph::addEdge(string start,string end,int wt) { city[make_pair(start,end)] = wt; } void Graph::display() {
int flag=0;
for(auto it:city)
{
city1.push_back(it.first.first);
city2.push_back(it.first.second);
}
sort(city1.begin(), city1.end());
auto last = unique(city1.begin(), city1.end());
city1.erase(last, city1.end());
sort(city2.begin(), city2.end());
auto last2 = unique(city2.begin(), city2.end());
city2.erase(last2, city2.end());
for(auto col:city2)
{
cout<<"\t"<<col;
}
cout<<"\n";
for(auto row:city1)
{
int flag =0; //for printing row for once
for(auto col:city2)
{
if (!flag)
cout<<row;
cout<<"\t"<<city[make_pair(row,col)];
flag = 1;
}
cout<<"\n";
}
} int main() {
Graph g(2);
g.addEdge("A","B",1);
g.addEdge("C","A",5);
g.addEdge("D","E",7);
g.addEdge("E","A",5);
g.addEdge("D","B",7);
g.addEdge("D","L",7);
g.addEdge("W","L",7);
g.display();
return 0; }
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.