I'm trying to implement graph as the Arc List, and while this implementation works efficiency is horrible, anything i missed that's making it so slow? Time was measured as the average of looking for arcs from/to each node.
struct Arc
{
int start;
int end;
Arc(int start,int end)
: start(start),
end(end)
{ }
};
typedef vector<Arc> ArcList;
class AListGraph
{
public:
AListGraph(IMatrix* in); //Fills the data from Incidence Matrix
bool IsE(int va,int vb); //checks if arc exists a->b
int CountEdges(); //counts all the arcs
int CountNext(int v); //counts all outgoing arcs from v
int CountPrev(int v); //counts all arcs incoming to v
private:
ArcList L;
int VCount;
};
//Cut out constructor for clarity
int AListGraph::CountEdges()
{
return L.size();
}
int AListGraph::CountNext(int v)
{
int result=0;
for(ArcList::iterator it =L.begin();it!=L.end();it++)
{
if(it->end==v)result++;
}
return result;
}
int AListGraph::CountPrev(int v)
{
int result=0;
for(ArcList::iterator it =L.begin();it!=L.end();it++)
{
if(it->start==v)result++;
}
return result;
}
Well, your implemention is worst possible : in order to find the in/out edges you have go across the whole graph.
Do you really need an arc list? Usually an adjacency list is much more efficient.
A naïve implementation of an adjacency list would be to keep an vector > arcs where the size of the arc is the number of nodes.
Given an node u, arcs[u] gives you all the out edges. You can figure out how to optimize it for in edges also.
Related
Here is the question link.
Given an undirected graph. Density of a graph is |E|⁄|V|. Your task is to choose non-empty set of vertices V such that subgraph induced on V has maximal density and print this density. But if maximal density is strictly greater than 1, just print ">1".
Maximum number of vertices: 105
Maximum number of edges: 105
I just made a simple solution, but in this solution I can keep track of the whole graph, but how do I get the value of density for smaller subGraphs?
#include<iostream>
#include<vector>
using namespace std;
vector<int> adj[1000002]; // adjacency lists adj for storing graph edges
int node=0; // initializing for node value(vertices)
bool visited[100001]={false}; // keeps track of visited nodes(vertices)
int edge=-1;
int ans=-1;
int n; // keeps optimum value of no. of nodes
int e; // keeps optimum value of no. of edges
void dfs(int s)
{
node++;
edge++;
if(edge>0)
{
float dummy=(float)edge/(float)node;
if(dummy>ans)
{ans=dummy;
e=edge;
n=node;
}
}
visited[s]=true;
int t;
for(int i=0;i!=adj[s].size();i++)
{ t=adj[s][i];
if(visited[t]==false)
{
dfs(t);
}
}
}
int main()
{
long long v,ed,i,j,x,y;
cin>>v>>ed;
for(long long k=0;k<ed;k++)
{
cin>>x>>y;
adj[x].push_back(y);
adj[y].push_back(x);
}
if(ed>v)
cout<<">1"<<endl;
else{
for(i=1;i<=v;i++)
{
if(visited[i]==false)
{
node=0;
edge=-1;
dfs(i);
//cout<<e<<"/"<<n<<endl;
}
}
cout<<e<<"/"<<n<<endl;}
}
Follow these steps to get better result:
1.Do a dfs on each component to get the answer.
2.Avoid the floating point calculation you are doing and try all integer calculation.
3.No reason to use long long here with that range
Change the code to something like this should work:
#include<iostream>
#include<vector>
using namespace std;
vector<int> adj[1000002]; // adjacency lists adj for storing graph edges
int node=0; // initializing for node value(vertices)
bool visited[100001]={false}; // keeps track of visited nodes(vertices)
int edge=0;
void dfs(int s)
{
node++;
visited[s]=true;
int t;
edge+=adj[s].size();
for(int i=0;i!=adj[s].size();i++)
{
t=adj[s][i];
if(visited[t]==false)
{
dfs(t);
}
}
}
int main()
{
int v,ed,i,j,x,y;
cin>>v>>ed;
for(int k=0;k<ed;k++)
{
cin>>x>>y;
adj[x].push_back(y);
adj[y].push_back(x);
}
int mark[3]; mark[0]=mark[1]=mark[2]=0;
int mx_node=0;
for(i=1;i<=v;i++)
{
if(visited[i]==false)
{
node=0;
edge=0;
dfs(i);
edge/=2;
if(node>edge){
mark[0]=1;
mx_node=mx_node<node?node:mx_node;
}
else if(node==edge) mark[1]=1;
else mark[2]=1;
}
}
if(mark[2]) printf(">1\n");
else if(mark[1]) printf("1\n");
else printf("%d/%d\n",mx_node-1,mx_node);
}
The input is in the following format
5
1 2 9.0
1 3 12.0
2 4 18.0
2 3 6.0
2 5 20.0
3 5 15.0
0
1 5
The first number is the number of vertexes in the graph. Then next lines up to 0 are the edges of the graph. With the first and second numbers being the vertexes and the third being how far the edge is between them. Trying to read in the data and store the edges into there locations in the List adjacency for that vertex. This example would make a graph with five vertexes with edges from 1 to 2&3. 2 to 4&3&1 etc.
I am getting a Segmentation fault after entering four numbers. The fault is happening on line myGraph.vertexInfo[p1].adjacency -> vertex=p2; where is starts trying to store the information. Why am I getting this fault?
#include <cstdio>
using namespace std;
struct ListCell
{
ListCell* next;
int vertex;
double weight;
ListCell(int v, double w, ListCell* nxt)
{
vertex = v;
weight = w;
next = nxt;
}
};
typedef ListCell* List;
struct Vertex
{
bool signaled;
long distance;
List adjacency;
};
struct Graph
{
int numVertices;
Vertex* vertexInfo;
Graph(int n)
{
numVertices = n;
vertexInfo = new Vertex[n+1];
for(int i = 1; i <= n; i++)
{
vertexInfo[i].signaled = false;
}
}
};
//==============================================================
// readIn
//==============================================================
//
//==============================================================
void readIn()
{
int g;
int p1;
int p2;
float edge;
scanf("%i ", &g);
Graph myGraph(g);
scanf("%i", &p1);
while(p1 != 0)
{
scanf("%i", &p2);
scanf("%f", &edge);
myGraph.vertexInfo[p1].adjacency -> vertex=p2;
myGraph.vertexInfo[p2].adjacency -> vertex=p1;
myGraph.vertexInfo[p1].adjacency -> weight=edge;
myGraph.vertexInfo[p2].adjacency -> weight=edge;
scanf("%i", &p1);
}
}
//==============================================================
// main
//==============================================================
int main(int argc, char** argv)
{
readIn();
return 0;
}
You are not following some of the fundamental principles of object construction and intialization for Vertex.
When you construct an instance of Vertex, there is nothing predictable about the values of the member data. I would suggest adding a default constructor that initializes the member data to something sane.
struct Vertex
{
Vertex() : signaled(false), distance(0), adjacency(NULL) {}
bool signaled;
long distance;
List adjacency;
};
Once you do that, the constructor for Graph can be simplified to:
Graph(int n) : numVertices(n)
{
vertexInfo = new Vertex[n+1];
}
Let's look at what adjacency is:
struct Vertex
{
bool signaled;
long distance;
List adjacency;
};
And now let's look at what List is:
typedef ListCell* List;
So, adjacency is actually a pointer to a ListCell. That's fine, we can work with that. But before we can, we must make sure that adjacency actually points to something. The question then becomes what does adjacency point to in your code?
The answer is: who knows? You never make it point to anything, so it's pointing somewhere randomly. And what happens when you try to write to some random area of memory? Well, if you're lucky, you crash.
So, how do you solve this problem? Simple: initialize and manipulate adjacency correctly. You may wish to look into dynamic memory allocation in C++ and the standard library which provides a rather nifty and working implementation of a linked list.
Sidenote: you seem to treat adjacency as a linked list. However, you ought to note that adjacency is a pointer to a node in a linked list. Again, now would a great time to learn about std::list.
The adjacency pointer is uninitialized, so you run into problems when dereferencing it.
You have to initialize your adjacency member:
Graph(int n)
{
numVertices = n;
vertexInfo = new Vertex[n+1];
for(int i = 1; i <= n; i++)
{
vertexInfo[i].signaled = false;
vertexInfo[i].adjacency = new ListCell(i, 0.0, 0);
}
}
Below is an implementation of Dijkstra's algorithm I wrote from the pseudocode in the Wikipedia article. For a graph with about 40 000 nodes and 80 000 edges, it takes 3 or 4 minutes to run. Is that anything like the right order of magnitude? If not, what's wrong with my implementation?
struct DijkstraVertex {
int index;
vector<int> adj;
vector<double> weights;
double dist;
int prev;
bool opt;
DijkstraVertex(int vertexIndex, vector<int> adjacentVertices, vector<double> edgeWeights) {
index = vertexIndex;
adj = adjacentVertices;
weights = edgeWeights;
dist = numeric_limits<double>::infinity();
prev = -1; // "undefined" node
opt = false; // unoptimized node
}
};
void dijsktra(vector<DijkstraVertex*> graph, int source, vector<double> &dist, vector<int> &prev) {
vector<DijkstraVertex*> Q(G); // set of unoptimized nodes
G[source]->dist = 0;
while (!Q.empty()) {
sort(Q.begin(), Q.end(), dijkstraDistComp); // sort nodes in Q by dist from source
DijkstraVertex* u = Q.front(); // u = node in Q with lowest dist
u->opt = true;
Q.erase(Q.begin());
if (u->dist == numeric_limits<double>::infinity()) {
break; // all remaining vertices are inaccessible from the source
}
for (int i = 0; i < (signed)u->adj.size(); i++) { // for each neighbour of u not in Q
DijkstraVertex* v = G[u->adj[i]];
if (!v->opt) {
double alt = u->dist + u->weights[i];
if (alt < v->dist) {
v->dist = alt;
v->prev = u->index;
}
}
}
}
for (int i = 0; i < (signed)G.size(); i++) {
assert(G[i] != NULL);
dist.push_back(G[i]->dist); // transfer data to dist for output
prev.push_back(G[i]->prev); // transfer data to prev for output
}
}
There are several things you can improve on this:
implementing the priority queue with sort and erase adds a factor of |E| to the runtime - use the heap functions of the STL to get a log(N) insertion and removal into the queue.
do not put all the nodes in the queue at once but only those where you have discovered a path (which may or may not be the optimal, as you can find an indirect path through nodes in the queue).
creating objects for every node creates unneccessary memory fragmentation. If you care about squeezing out the last 5-10%, you could think about a solution to represent the incidence matrix and other information directly as arrays.
Use priority_queue.
My Dijkstra implementation:
struct edge
{
int v,w;
edge(int _w,int _v):w(_w),v(_v){}
};
vector<vector<edge> > g;
enum color {white,gray,black};
vector<int> dijkstra(int s)
{
int n=g.size();
vector<int> d(n,-1);
vector<color> c(n,white);
d[s]=0;
c[s]=gray;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > q; // declare priority_queue
q.push(make_pair(d[s],s)); //push starting vertex
while(!q.empty())
{
int u=q.top().second;q.pop(); //pop vertex from queue
if(c[u]==black)continue;
c[u]=black;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i].v,w=g[u][i].w;
if(c[v]==white) //new vertex found
{
d[v]=d[u]+w;
c[v]=gray;
q.push(make_pair(d[v],v)); //add vertex to queue
}
else if(c[v]==gray && d[v]>d[u]+w) //shorter path to gray vertex found
{
d[v]=d[u]+w;
q.push(make_pair(d[v],v)); //push this vertex to queue
}
}
}
return d;
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
C++ how to sort vector<class *> with operator <
Hello everyone!
Please i am trying to sort a vector of type "class" based on one of its data members. As follows:
The Header File: (Undirected_Graph.h)
#ifndef UNDIRECTED_GRAPH_H
#define UNDIRECTED_GRAPH_H
#include <vector>
using std::vector;
#include <climits>
class Edge;
class Node
{
public:
Node(int); //The constructor.
int id; //For the id of the node.
bool visited; //For checking visited nodes.
int distance;
vector <Edge*> adj; //The adjacent nodes.
};
class Edge
{
public:
Edge(Node*, Node*, int); //The constructor.
Node* start_Node; //The start_Node start of the edge.
Node* end_Node; //The end of the edge.
int w; //The weight of the edge.
bool isConnected(Node* node1, Node* node2) //Checks if the nodes are connected.
{
return((node1 == this->start_Node && node2 == this->end_Node) ||
(node1 == this->end_Node && node2 == this->start_Node));
}
};
class Graph
{
public:
Graph(int); //The Constructor.
int max_Nodes; //Maximum Number of allowed Nodes.
vector <Edge*> edges_List; //For storing the edges of the graph.
vector <Node*> nodes_List; //For storing the nodes of the graph.
void insertEdge(int, int, int);
int getNumNodes();
int getNumEdges();
};
#endif
The Implementation File: (Undirected_Graph.cpp)
#include "Undirected_Graph.h"
Node::Node(int id_Num)
{
id = id_Num;
visited = 0;
distance = INT_MAX;
}
Edge::Edge(Node* a, Node* b, int weight)
{
start_Node = a;
end_Node = b;
w = weight;
}
Graph::Graph(int size)
{
max_Nodes = size;
for (int i = 1; i <= max_Nodes; ++i)
{
Node* temp = new Node(i);
nodes_List.push_back(temp);
}
}
void Graph::insertEdge(int x, int y, int w)
{
Node* a = nodes_List[x-1];
Node* b = nodes_List[y-1];
Edge* edge1 = new Edge(a, b, w);
Edge* edge2 = new Edge(b, a, w);
edges_List.push_back(edge1);
a->adj.push_back(edge1);
b->adj.push_back(edge2);
}
int Graph::getNumNodes()
{
return max_Nodes;
}
int Graph::getNumEdges()
{
return edges_List.size();
}
Now in the above code, after creating several nodes and edges, i need to sort the edges of this graph based on their weight. I am studying a way to implement Kruskal algorithm so i though of sorting the edges first based on their weight.
sort (myGraph.edges_List[index].begin(), myGraph.edges_List[index].end());
obviously does not work! since the vector edges_List is of type "Edge".
Assuming that (myGraph is an object of the class).
I was wondering if there is any good technique to do that?
Thanks in advance for your help! Any suggestions or ideas are greatly appreciated!
By default, std::sort uses using operator<, but you can also supply a comparison function object.
So:
bool your_comparer(const Edge * left, const Edge * right)
{
// return true if left should come before right, false otherwise
}
// ...
sort (myGraph.edges_List.begin(), myGraph.edges_List.end(), your_comparer);
Another way is usage std::set container for storing your objects. And you always will have sorted container. All you need is define operator < for stored classes.
Usage vector with push_back is not effective way in terms of time. It cause unnecessary memory rellocations.
Hey, I'm AI Student and gonna try my homework that is implementation of A* algorithm in order to traversal a graph. i use c++ codes and what i made for now is below code which is only a Graph class + insertedge and vertices functions.
but now i'm confused of how to define cost function (f= h(n) + g(n)) ...
also any code refrence or explain of how A* works for graphs would help me . what i found in google was about pathfinding via a* and it has nothing with traversal graph.
#include <iostream>
using namespace std;
class Graph;
class node {
friend class Graph;
private:
char data;
int cost;
node *next;
node *vlist;
bool goal;
bool visited;
public:
node(char d,int c, bool g){
cost = c;
goal = g;
next = NULL;
data = d;
vlist = NULL;
visited = false;
}
};
class Graph {
private:
node *Headnodes;
char n;
public:
Graph ()
{
Headnodes = NULL;
}
void InsertVertex(char n, int c, bool g);
void InsertEdge(char n, char m, int c);
void PrintVertices();
void Expand(char n);
};
/////////////////
// INSERTION //
/////////////////
void Graph::InsertVertex(char n, int c, bool g){
node *temp = new node(n,c,g);
if(Headnodes==NULL)
{
Headnodes=temp;
return;
}
node *t=Headnodes;
while(t->vlist!=NULL)
t=t->vlist;
t->vlist=temp;
}
void Graph::InsertEdge(char n, char m, int c){
int temp_cost = 0;
if(Headnodes==NULL)
return;
node *x=Headnodes;
while(x!=NULL){
if(x->data==m)
temp_cost = (x->cost+c);
x = x->vlist;
}
node *t=Headnodes;
node *temp=new node(m,temp_cost,false);
while(t!=NULL){
if(t->data==n){
node *s=t;
while(s->next!=NULL)
s=s->next;
s->next=temp;
}
t=t->vlist;
}
}
int min_cost = 1000;
bool enough = false;
void Graph::PrintVertices(){
node *t=Headnodes;
while(t!=NULL){
cout<<t->data<<"\t";
t=t->vlist;
}
}
void Graph::Expand(char n){
cout << n << "\t";
char temp_min;
node *t=Headnodes;
while(t!=NULL){
if(t->data==n && t->visited == false){
t->visited = true;
if (t->goal)
return;
while(t->next!=NULL){
if (t->next->cost <= min_cost){
min_cost=t->next->cost;
temp_min = t->next->data;
}
t = t->next;
}
}
t=t->vlist;
}
Expand(temp_min);
}
int main(){
Graph g;
g.InsertVertex('A',5,false);
g.InsertVertex('B',1,false);
g.InsertVertex('C',9,false);
g.InsertVertex('D',5,false);
g.InsertVertex('E',1,false);
g.InsertVertex('F',3,false);
g.InsertVertex('G',2,false);
g.InsertVertex('J',1,false);
g.InsertVertex('K',0,true);
g.InsertEdge('A','B',2);
g.InsertEdge('A','C',1);
g.InsertEdge('B','A',2);
g.InsertEdge('B','D',1);
g.InsertEdge('B','E',1);
g.InsertEdge('C','A',1);
g.InsertEdge('C','F',1);
g.InsertEdge('C','G',1);
g.InsertEdge('E','J',3);
g.InsertEdge('E','K',3);
g.PrintVertices();
cout<<"\n\n";
g.Expand('A');
return 0;
}
What you have is only a graph search algorithm.
You forgot the essence of the A* algorithm, that is the h(n) cost, that comes from an heuristic calculation.
You have to implement a method, the h(n) that will calculate, based on yours heuritics, the possible cost from actual path to the final path, and this value will be used to calculate the walking cost:
f'(n) = g(n) + h'(n), being the g(n) the already know cost, at your case, the x->cost.
g(n) is the total distance cost it has
taken to get from the starting
position to the current location.
h'(n) is the estimated distance cost from
the current position to the goal
destination/state. A heuristic
function is used to create this
estimate on how far away it will take
to reach the goal state.
f'(n) is the sum of g(n) and h'(n).
This is the current estimated shortest
path. f(n) is the true shortest path
which is not discovered until the A*
algorithm is finished.
So, what you have to do:
Implement a method heuristic_cost(actual_node, final_node);
Use this value together with the actual cost, like the equation before, by example: min_cost=t->next->cost + heuristic_cost(t->next, final_node) ;
I really like the explanation here: Link , cleaner than wikipedia's explanation.