I was learning the dijkstra's algorithm and then in that there was the concept of priority queue with min_heap implementation where my priority_queue <Node,vector<Node>,comp> min_heap and the comp is a comparison struct;
struct Edge{
int src;
int dest;
int weight;
};
struct Node{
int vertex;
int weight;
};
class Graph{
public:
vector<vector<Edge>> adjList;
Graph(vector<Edge> &edges,int N){
adjList.resize(N);
for(auto &edge:edges){
adjList[edge.src].push_back(edge);
}
}
};
struct comp{
bool operator()(const Node &lhs,const Node &rhs) const{
return lhs.weight>rhs.weight;
}
};
void dij(Graph g,int source,int N){
priority_queue<Node,vector<Node>,comp> min_heap;
min_heap.push({source,0});
vector<int> dist(N,INT_MAX);
dist[source] = 0;
vector<bool> done(N,false);
done[0] = true;
while(!min_heap.empty()){
Node node = min_heap.top();
min_heap.pop();
int u = node.vertex;
for(auto i:g.adjList[u]){
int v = i.dest;
int weight = i.weight;
if(!done[u] && dist[u]+weight<dist[v]){
dist[v] = dist[u] + weight;
min_heap.push({v,dist[v]});
}
}
done[u] = true;
}
cout<<"The path from vertex "<<source<<" to "<<N<<" is "<<dist[N];
}
The code works fine and prints the minimum cost but I am not understanding the struct comp(); and how this works.
Related
I'm trying to loop through my adjacency list in my DFS search class, but its giving me this error: type 'AdjList' does not provide a subscript operator. I feel like it might be the way i saved adjList constructor for DFS but I'm not sure. I saw other solutions saw it has to be passed as a pointer so I changed AdjList list in the constructor to AdjList* list but that did not work. Here is my code:
main.cpp
AdjList::AdjList(){}
AdjList::AdjList(vector<Node> nodeVector){
nodeContainer = nodeVector;
}
void AdjList::makeAdjList(){
int temp;
for(int i = 0; i < nodeContainer.size(); i++){
connections = nodeContainer[i].getConnectionsVector();
for(int x = 0; x < connections.size(); x++){
innerList.push_back(nodeContainer[connections[x] - 1]);
}
adjList.push_back(innerList);
innerList.clear();
}
}
//other AdjList functions
int main(){
vector<Node> nodeContainer;
nodeContainer = load();
AdjList adjList(nodeContainer);
adjList.makeAdjList();
DFS search(nodeContainer, adjList);
search.iterative(6,3);
}
DFS.cpp
DFS::DFS(vector<Node> nodeVec, AdjList list){
nodeContainer = nodeVec;
adjList = list;
}
vector<Node> DFS::iterative(int src, int dest){
vector<Node> vectorPath;
list<Node>::iterator it;
int i = 6;
for(it = adjList[i].begin(); it != adjList[i].end(); it++){ //this is where the
//error is happening
cout << it->getNodeID() << " ";
}
return vectorPath;
}
AdjList.h
class AdjList{
private:
public:
list<Node> innerList;
vector<list<Node> > adjList;
vector<Node> nodeContainer;
vector<int> connections;
int temp;
AdjList();
AdjList(vector<Node> nodeVector);
void makeAdjList();
void displayAdjList();
};
When you say adjList[i], C++ looks for an operator[] in the type of adjList which is AdjList. As this type doesn't have such a member function you get the error message that it's missing.
Supply a
std::list<Node>& operator[](std::size_t i);
std::list<Node> const& operator[](std::size_t i) const;
and return adjList[i] in both.
I'm trying to build a graph class where the graph is represented by adjacency lists. The graph itself is a vector of pointers where each pointer points to a linked list of nodes. For whatever reason, when I use the print graph function the program outputs nothing. Can anyone show me what I am doing wrong and perhaps where my misunderstanding of pointers is? Thanks in advance!
#include <array>
#include <vector>
#include <tuple>
#include <unordered_map>
class Node
{
public:
int vertex;
int value;
Node* next;
Node(int ver)
{
vertex = ver;
};
};
class Graph
{
public:
int n_nodes;
std::unordered_map<int,Node*> graph;
Graph(int n)
{
n_nodes = n;
for(int i=0;i<n;i++)
{
graph.insert({i,nullptr});
};
};
void add_edge(int src,int des,int val)
{
Node node_des = Node(des);
node_des.value = val;
node_des.next = graph[src];
graph[src] = &node_des;
Node node_src = Node(src);
node_src.value = val;
node_src.next = graph[des];
graph[des] = &node_src;
};
void print_graph()
{
for(int i =0; i<n_nodes;i++)
{
std::string str = "Head "+std::to_string(i);
Node node = *graph[i];
while (&node != nullptr)
{
str=str+" -> "+std::to_string(node.vertex);
node = *(node.next);
};
std::cout<<str<<std::endl;
};
};
};
int main()
{
Graph g = Graph(6);
g.add_edge(0,1,3);
g.add_edge(2,1,4);
g.add_edge(0,4,1);
g.add_edge(4,5,6);
g.add_edge(5,3,2);
g.add_edge(4,3,3);
g.add_edge(3,2,5);
g.add_edge(4,1,1);
g.add_edge(3,1,2);
g.print_graph();
return 0;
}```
If it´s possible, you may just use vector of vector instead of linked lists and not use pointers at all. Because memory cache some insertions in vectors operations may be faster than linked lists, a structure like :
struct Node2 {
int vertex;
int value;
};
struct Edge2 {
int src, des, value;
};
struct Graph2 {
int n_nodes;
std::vector<std::vector<Node2>> graph;
void add_edge(Edge2 edge) {
graph[edge.src].emplace_back(edge.des, edge.value);
graph[edge.des].emplace_back(edge.src, edge.value);
}
void add_edge(std::initializer_list<Edge2> edges)
{
std::for_each(edges.begin(), edges.end(), [this](auto &e) { add_edge(e); });
};
}
Endup bening easier and faster than linked lists;
https://quick-bench.com/q/cmX2-2IYA873TR4qn5aV4ijjUQo
Made these changes thanks to #drescherjm. The issue was that I had created a local variable and referenced its address instead of explicitly creating a pointer and setting it to a new node instance where the object's lifetime is dynamically controlled.
#include <bits/stdc++.h>
#include <array>
#include <vector>
#include <tuple>
#include <unordered_map>
class Node
{
public:
int vertex;
int value;
Node* next;
Node(int ver)
{
vertex = ver;
};
};
class Graph
{
public:
int n_nodes;
std::unordered_map<int,Node*> graph;
Graph(int n)
{
n_nodes = n;
for(int i=0;i<n;i++)
{
graph.insert({i,nullptr});
};
};
void add_edge(int src,int des,int val)
{
Node * node_des = new Node(des);
node_des->value = val;
node_des->next = graph[src];
graph[src] = node_des;
Node * node_src = new Node(src);
node_src->value = val;
node_src->next = graph[des];
graph[des] = node_src;
};
void print_graph()
{
for(int i =0; i<n_nodes;i++)
{
std::string str = "Head "+std::to_string(i);
Node * node_ptr = graph[i];
while (node_ptr != nullptr)
{
str=str+" -> "+std::to_string(node_ptr->vertex);
node_ptr = node_ptr->next;
};
std::cout<<str<<std::endl;
};
};
};
int main()
{
Graph g = Graph(6);
g.add_edge(0,1,3);
g.add_edge(2,1,4);
g.add_edge(0,4,1);
g.add_edge(4,5,6);
g.add_edge(5,3,2);
g.add_edge(4,3,3);
g.add_edge(3,2,5);
g.add_edge(4,1,1);
g.add_edge(3,1,2);
g.print_graph();
return 0;
}
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;
}
I've a question to ask.
So, I have a structure call Node as shown below:
struct Node
{
int xKoor, yKoor;
Node *parent;
char nodeId;
float G;
float H;
float F;
Node(int x, int y, int id, Node * par)
{
xKoor = x;
yKoor = y;
nodeId = id;
parent = 0;
}
Node(int x, int y, char id)
{
xKoor = x;
yKoor = y;
nodeId = id;
}
};
And I have list that contains elements of this structure:
list<Node*> OPEN;
This list's size varies in time.
What I need to do is to find the Node object which has the minimum F value, then pop out that object from the list.
So, I tried to write a function as shown below:
void enKucukFliNodeBul(list<Node*> OPEN)
{
list<Node*>::iterator it = OPEN.begin();
for(it = OPEN.begin(); it != OPEN.end(); it++)
{
if(it._Ptr->_Myval->F < it._Ptr->_Next->_Myval->F)
{
}
}
}
But I'm stuck. I'm new to STL. How can I solve this?
My best regards...
You can use std::min_element with a suitable comparison function for this.
bool nodeComp(const Node* lhs, const Node* rhs) {
return lhs->F < rhs->F;
}
#include <algorithm> // for std::min_element
list<Node*>::iterator it = std::min_element(OPEN.begin(), OPEN.end(), nodeComp);
This assumes that list<Node*> is std::list<Node*>, in which case you should be aware that std::list itself is a linked list.
Other useful operations, based on your comments:
Remove a minimum value node from the list and delete it:
OPEN.erase(it);
delete *it; //
You may need to perform other operations, if your nodes depend on each other.
Sort the list:
OPEN.sort(nodeComp);
use std::min_element algirithm and overload Compare function
bool compareF(Node *lhs, Node *rhs)
{
return lhs->F < rhs->F;
}
if you are using C++03:
std::<Node*>::itertor ter = std::min_element(OPEN.begin(),OPEN.end(), compareF);
if you are using C++11:
auto iter = std::min_element(OPEN.begin(),OPEN.end(), compareF);
To sort the list, you can call OPEN.sort(compareF); to sort your list with compareF function
Try adding this:
bool compare_node_F(Node* n1, Node* n2)
{
return n1-> F< n2-> F;
}
#include <list>
#include <algorithm>
#include <cstdlib>
#include <iostream>
int main()
{
std::list<Node*> nodes;
for(int i= 100; i--;)
{
Node* n= new Node(42, 42, 42);
n-> F= i;
nodes.push_back(n);
}
std::list<Node*>::iterator min_element_iter= std::min_element(nodes.begin(), nodes.end(), compare_node_F);
std::cout<< "Min F: "<< (*min_element_iter)-> F<< '\n';
for(std::list<Node*>::iterator d= nodes.begin(); d!= nodes.end(); ++ d)
delete *d;
}
I have a question about inheritance. From this source:
gSpan.h
struct Edge {
int from;
int to;
int elabel;
unsigned int id;
Edge(): from(0), to(0), elabel(0), id(0) {};
};
class Vertex
{
public:
typedef std::vector<Edge>::iterator edge_iterator;
int label;
std::vector<Edge> edge;
void push (int from, int to, int elabel) //elabel代表edge label
{
edge.resize (edge.size()+1);
edge[edge.size()-1].from = from;
edge[edge.size()-1].to = to;
edge[edge.size()-1].elabel = elabel;
return;
}
};
class Graph: public std::vector<Vertex> {
public:
typedef std::vector<Vertex>::iterator vertex_iterator;
Graph (bool _directed)
{
directed = _directed;
};
bool directed;
Graph(): edge_size_(0), directed(false) {};
};
gSpan.cpp
std::istream &gSpan::read (std::istream &is)
{
Graph g(directed);
while (true) {
g.read (is);
if (g.empty()) break;
TRANS.push_back (g);
}
return is;
}
graph.cpp
std::istream &Graph::read (std::istream &is)
{
std::vector <std::string> result;
char line[1024];
while (true) {
if (result.empty()) {
// do nothing
} else if (result[0] == "t") {
...
} else if (result[0] == "v" && result.size() >= 3) {
unsigned int id = atoi (result[1].c_str());
this->resize (id + 1);
(*this)[id].label = atoi (result[2].c_str());
...
Why we can use (*this)[id].label in graph.cpp? (*this) is a Graph object.... if we want to use (*this)[id].label shouldn't we have to declare std::vector<Vertex>?
class Graph: public std::vector<Vertex>
This means that the Graph class inherited std::vector<Vertex>, so you can do anything with it that you'd be able to do if it were a vector. And so by creating an instance of Graph, you're effectively declaring a new vector.