My Dijkstra algorithm's not choosing the shortes path - c++

i tried to code Dijkstra algorithm with two custom structs of vertexes and their edges for my custom graph, the algorithm compiles but it makes wrong choice choosing the best distance. the code is as following.
class Graph {
struct Edge;
struct Vertex {
std::string _data; //name of vertex
std::list<Edge*> _ins;
std::list<Edge*> _outs;
bool visited;
int BestDist;//best distance from source to sink
};
struct Edge {
int _weight;
Vertex *_from;
Vertex *_to;
bool travelled; //if the edge has been travalled
};
//Graph of String as key to Values as vertexes
std::unordered_map<std::string, Vertex *> _mainData;
//Dijkstra Algo
int BestDistance(std::string source, std::string sink) {
//to save vertexes names
std::queue<std::string> q;
//for each vertex set dist and path to infinity
for (auto startItr : _mainData)
{
startItr.second->BestDist = Max;
startItr.second->visited = false;
for (auto kachal : startItr.second->_outs)
{
kachal->travelled = false;
}
}
//set source distacne to 0 sicen it is visiting itself
_mainData[source]->BestDist = 0;
q.push(source);
//while there is unknown distance vertex and we havent reach sink yet
while (!q.empty() )
{
//smallest unknow distance vertex
std::string currentVer = q.front(); q.pop();
//set that vertex to visited
_mainData[currentVer]->visited = true;
//for each vertex adj to current vertex
for (auto adjVer : _mainData[currentVer]->_outs) {
//if that vertex is not visted
if (!adjVer->travelled) {
int cvw = adjVer->_weight; //cost of edge from cuurent vertex to adj vertex
//if current vert.distance +cvw < adj vertex distance
if (_mainData[currentVer]->BestDist + cvw < _mainData[adjVer->_to->_data]->BestDist) {
//update adj vertex
q.push(adjVer->_to->_data);
//deacrease adj vertex distacne to current distacne + cvw
_mainData[adjVer->_to->_data]->BestDist = _mainData[currentVer]->BestDist + cvw;
//marked the travlled edge true
adjVer->travelled = true;
}
}
}
}
return _mainData[sink]->BestDist;
}
and here is my main:
#include "stdafx.h"
#include "Graph.h"
#include <iostream>
int main()
{
Graph myGraph;
myGraph.Add("A");
myGraph.Add("B");
myGraph.Add("C");
myGraph.Add("D");
myGraph.Add("E");
myGraph.Add("F");
myGraph.Add("G");
myGraph.Connect("A", "B",20);
myGraph.Connect("A", "C",30);
myGraph.Connect("B", "D",200);
myGraph.Connect("C", "F",100);
myGraph.Connect("C", "G",200);
myGraph.Connect("D", "E",50);
myGraph.Connect("E", "F",1);
myGraph.Connect("F", "G",30);
std::cout << "best distacne example : " << myGraph.BestDistance("A", "G");
so when i run the code, the best distance from A to G shoudl be returned as 160 (A->C->F->G) but the code returns 280 which is (A->C->G). I can provide my Add and Connect functions but i'm sure they are working correctly.

so after analyzing above algorithm i realized my mistake was to mark each edge as being traveled or not and make decisions based on that. what i should have done was to mark each Vertex for being visited or not . the rest is ok. so this is the correct version of my implementation of Dijkstra Algorithm finding the shortest path in a positively weighted graph. hope it helps
//Dijkstra Algo
int BestDistance(std::string source, std::string sink) {
//to save vertexes names
std::queue<std::string> q;
//for each vertex set dist and path to infinity
for (auto startItr : _mainData)
{
startItr.second->BestDist = Max;
startItr.second->visited = false;
}
//set source distacne to 0 sicen it is visiting itself
_mainData[source]->BestDist = 0;
q.push(source);
//while there is unknown distance vertex and we havent reach sink yet
while (!q.empty() )
{
//smallest unknow distance vertex
std::string currentVer = q.front(); q.pop();
//set that vertex to visited
_mainData[currentVer]->visited = true;
//for each vertex adj to current vertex
for (auto adjVer : _mainData[currentVer]->_outs) {
//if that vertex is not visted
if (!adjVer->_to->visited) {
int cvw = adjVer->_weight; //cost of edge from cuurent
//vertex to adj vertex
//if current vert.distance +cvw < adj vertex distance
if (_mainData[currentVer]->BestDist + cvw <
_mainData[adjVer->_to->_data]->BestDist) {
q.push(adjVer->_to->_data);
//deacrease adj vertex distacne to current distacne + cvw
_mainData[adjVer->_to->_data]->BestDist = _mainData[currentVer]->BestDist + cvw;
//setting the path of adj vertext to his previous one
_mainData[adjVer->_to->_data]->path = _mainData[currentVer];
}
}
}
}
return _mainData[sink]->BestDist;
}

Related

How can you check if a sequence of nodes exists in an undirected graph, where each node is adjacent to the next?

I have an undirected graph of letters in a rectangular format, where each node has an edge to the adjacent neighboring node.
For example:
d x f p
o y a a
z t i b
l z t z
In this graph node "d" is adjacent to [x, y, o].
I want to check if the sequence of nodes "dot" exists in the graph, where each subsequent node is adjacent to the next. The main application is a word search game, where only words with adjacent letters count. For example, the sequence "zap" does NOT count, since the nodes are not adjacent. I do not need to check if the sequence is a real word, only that it is adjacent in the graph.
My graph.h is as follows:
// graph.h
#include <queue>
#include "SLList.h"
#include "DynArray.h"
template<typename Type>
class Graph {
public:
struct Edge {
unsigned int toVertex; // index to vertex the edge connects to
};
struct Vertex {
// the data that this vertex is storing
Type element;
// the list of edges that connect this vertex to another vertex
SLList<Edge> edges;
///////////////////////////////////////////////////////////////////////////
// Function : addEdge
// Parameters : toVertex - the index of the vertex we are adjacent to
///////////////////////////////////////////////////////////////////////////
void addEdge(const unsigned int& toVertex) {
Edge e;
e.toVertex = toVertex;
edges.addHead(e);
}
};
private:
// dynarray of vertices
DynArray<Vertex> vertices;
// helper function to check if a vertex is a in a queue
bool IsInQueue(DynArray<Edge> arrayOfEdges, unsigned int _toVertex) {
for (unsigned int i = 0; i < arrayOfEdges.size(); ++i) {
if (arrayOfEdges[i].toVertex == _toVertex)
return true;
}
return false;
}
public:
/////////////////////////////////////////////////////////////////////////////
// Function : addVertex
// Parameters : value - the data to store in this vertex
// Return : unsigned int - the index this vertex was added at
/////////////////////////////////////////////////////////////////////////////
unsigned int addVertex(const Type& value) {
Vertex v;
v.element = value;
vertices.append(v);
return vertices.size();
}
/////////////////////////////////////////////////////////////////////////////
// Function : operator[]
// Parameters : index - the index in the graph to access
// Return : Vertex& - the vertex stored at the specified index
/////////////////////////////////////////////////////////////////////////////
Vertex& operator[](const unsigned int& index) {
return vertices[index];
}
/////////////////////////////////////////////////////////////////////////////
// Function : size
// Return : unsiged int - the number of vertices in the graph
/////////////////////////////////////////////////////////////////////////////
unsigned int size() const {
return vertices.size();
}
/////////////////////////////////////////////////////////////////////////////
// Function : clear
// Notes : clears the graph and readies it for re-use
/////////////////////////////////////////////////////////////////////////////
void clear() {
// for each node, remove all its edges
// then remove the node from the array
for (unsigned int i = 0; i < vertices.size(); ++i) {
vertices[i].edges.clear();
}
vertices.clear();
}
};
So far I tried:
my algorithm:
finding the starting node
setting a current node to this start node
searching all edges of the current node for the next node in sequence without visiting nodes that have been visited
if next node in sequence is found then current is set to next and next is incremented
if current == end and next == null then return true
else false
However, this does not work every time. For example, it works for "dot", but not "pay" in the above graph. This is because once it visits the second "a" it marks as visited and cannot find "y" anymore. I believe there are other problems with this algorithm.
I have searched other answers on here, but they only explain how to find a path from a start node to an end node, where the path doesn't matter. In this case, the path is what matters.
Solution in c++ using my graph.h preferred.
Here is a simple Depth-First Search-based procedure that attempts to find a path that creates a specified string in a grid of characters. This DFS is an example of a basic brute-force algorithm, as it simply tries all possible paths that could be right. In the below program, I use my own Graph class (sorry), but it should be simple enough to understand. Here is my code in C++:
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
struct Graph{
int rows, cols;
vector <vector<char>> grid;
// DFS: Recursively tries all possible paths - SEE THE BELOW FUNCTION FIRST
void dfs(int r, int c, size_t len, string &str, bool &done, auto &vis, auto &path){
// if (len == str.size()), that means that we've found a path that
// corresponds to the whole string, meaning that we are done.
if(len == str.size()){
done = true;
return;
}
// Check all nodes surrounding the node at row r and column c
for(int next_r = r-1; next_r <= r+1; ++next_r){
for(int next_c = c-1; next_c <= c+1; ++next_c){
// Bounds check on next_r and next_c
if(next_r < 0 || next_r >= rows){continue;}
else if(next_c < 0 || next_c >= cols){continue;}
// KEY: We don't visit nodes that we have visited before!
if(vis[next_r][next_c]){
continue;
}
// ONLY if grid[next_r][next_c] happens to be the next character in str
// that we are looking for, recurse.
if(grid[next_r][next_c] == str[len]){
vis[next_r][next_c] = true;
path.push_back({next_r, next_c});
dfs(next_r, next_c, len + 1, str, done, vis, path);
// If done is true, that means we must've set it to true in
// the previous function call, which means we have found
// a valid path. This means we should keep return-ing.
if(done){return;}
vis[next_r][next_c] = false;
path.pop_back();
}
}
if(done){return;} // see the above comment
}
}
// Returns a vector <pair<int, int>> detailing the path, if any, in the grid
// that would produce str.
vector <pair<int, int>> get_path_of(string &str){
bool done = false;
vector <pair<int, int>> path;
// Try starting a DFS from every possible starting point until we find a valid
// path
for(int r = 0; r < rows; ++r){
for(int c = 0; c < cols; ++c){
vector <vector<bool>> vis(rows, vector <bool> (cols, false));
dfs(r, c, 0, str, done, vis, path);
// Found a path during the above function call! We can return now
if(done){
return path;
}
}
}
return {};
}
Graph(int r, int c){
rows = r;
cols = c;
grid = vector <vector<char>> (r, vector <char> (c));
}
};
int main()
{
// Input in the number of rows and columns in the grid
int R, C;
cin >> R >> C;
Graph G(R, C);
// Input the letters of the grid to G
for(int i = 0; i < R; ++i){
for(int j = 0; j < C; ++j){
cin >> G.grid[i][j];
}
}
// Input the strings to find in G
string str;
while(cin >> str){
vector <pair<int, int>> path = G.get_path_of(str);
cout << "PATH OF " << str << ": ";
for(const pair <int, int> &item : path){
cout << "{" << item.first << ", " << item.second << "} ";
}
cout << "\n";
}
return 0;
}
If you have any questions, please don't hesitate to ask!

bfsTree empty with unused value warning

I am trying to implement bfsTree. It should take a graph as input and give the bfs tree as output. However the line that adds the edge to the bfs tree seems to be not working. The bfstree is empty. I think it is related to this unused value warning. Why it gives the warning? And how to fix it? Thanks.
Here is the warning:
vertex.cpp:35:10: warning: expression result unused [-Wunused-value]
for (neighbor; neighbor != this->_neighbors.end(); neighbor++) {
Here is the bfs tree code snippet:
Graph Bicc::breadthFirstSearch(Graph& sparseGraph) {
Graph bfsTree;
auto lev = 0;
vector<Vertex> verticies = sparseGraph.getVerticies();
for(int i = 0; i < verticies.size(); i++){
verticies[i].color = "white";
verticies[i].level = lev;
}
Vertex start = verticies[0];
list<Vertex> VertexQueue;
VertexQueue.push_back(start);
while (!VertexQueue.empty())
{
Vertex current = VertexQueue.front();
current.color = "gray"; //current vertex is being processed
auto neighbors = current.getNeighbors();
//process all neighbors of current vertex
for(auto n = neighbors.begin(); n != neighbors.end(); n++) {
if (n->color == "white") { // This is an unvisited vertex
n->level = lev + 1; // Set level
n->parent = &current; // Set parent
n->color = "gray"; // Set color visited
bfsTree.add(current, *n); //add the edge to bfsTree
VertexQueue.push_back(*n); // Add it to the queue
}
}
VertexQueue.pop_front(); // Pop out the processed vertex
++lev; // The next level
}
return bfsTree;
}
Here is the vertex.cpp code snippet that was called by the warning:
bool Vertex::hasNeighbor(const Vertex& vertex) const {
auto neighbor = this->_neighbors.begin();
for (neighbor; neighbor != this->_neighbors.end(); neighbor++) {
if (*neighbor == vertex) {
break;
}
}
return neighbor != this->_neighbors.end();
}

degree of connection between 2 nodes in a social graph

I'm trying to find out the degree of connection between 2 entities in a social graph where
1 hop : 1st Degree
2 hop : 2nd Degree
3 hop : 3rd Degree
And so on.
The vertices are the entities and the edges are the friendship between the two entities. Given such a graph I want to analyse the graph and answer the query as to what is the type of connection between the entities.It can be disconnected graph.In case of no connection it'll return 0.
It takes the input as-
Number_of_vertices Number_of_Edges
Edge 1
Edge 2
(So on.)
Query
Output
The degree of connection
Example
Input
5 4
Abhs Krax // Edge 1
Harry Idrina // Edge 2
Harry Jigma // Edge 3
Harry Krax // Edge 4
Abhs Jigma // Query
Output
Degree : 3
I've used BFS to find out the depth between 2 nodes, but my program works only for degree 1. It fails to test the next subsequent member of the queue thus stuck at testing only the 1st member of the queue. What did I miss in my code? The problem is in Connection() function which I couldn't trace.
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Vertex // Each vertex of the graph is represented by the object of the Vertex class
{
public:
// Fields in every vertex node
string name;
std::list<Vertex*> adjacencyList;
bool status;
int depth;
// Constructor which initializes the node
Vertex(string id)
{
name = id;
adjacencyList = list<Vertex*>();
status = false;
depth =0;
}
// Function to add edges by pushing the vertices to its adjacency list
void addEdge(Vertex *v)
{
adjacencyList.push_back(v);
}
};
class Graph{
public:
// Fields of the Graph node
int N;
std::list<Vertex> vertexList;
// Functions to be implemented
int Connection(Vertex,Vertex);
Graph(int n){ // Constructor
N = n;
vertexList = list<Vertex>();
}
/* This function first checks whether the vertex has been already added
to Vertex List of the Graph. If not found it would create the vertex
node and push the node into Vertex List. Then the edges are added by
updating the adjacency list of respective vertices. */
void addEdge(string to, string from ){
if(find(to))
{
Vertex entity_1 = Vertex(to); // New vertex node creation
vertexList.push_back(entity_1); // Pushing to the Vertex List
}
if(find(from))
{
Vertex entity_2 = Vertex(from);
vertexList.push_back(entity_2);
}
Vertex *v1 = &(*(find_it(to)));
Vertex *v2 = &(*(find_it(from)));
v1->addEdge(v2); // Updating respective adjacency list
v2->addEdge(v1);
}
// Function to check whether the vertex is already added in the Vertex List
int find(string check)
{
list<Vertex>::iterator it;
it = find_it(check);
if(it==vertexList.end())
return 1;
else
return 0;
}
// Function which returns pointer to a Vertex in the Vertex List
list<Vertex>::iterator find_it(string check)
{
list<Vertex>::iterator it;
for (it = vertexList.begin(); it != vertexList.end(); it++)
if((check.compare(it->name))==0)
break;
return it;
}
};
int main()
{
int numVertices,numEdges,i,result;
string to,from,queryTo,queryFrom;
cin>>numVertices>>numEdges;
Graph G = Graph(numVertices); // Creating the Graph object
for( i=0;i<numEdges;i++)
{
cin>>to>>from;
G.addEdge(to,from); // Adding Edges to Graph
}
cin>>queryTo>>queryFrom;
// The function you have to write is called here where the address of vertex
// node is passed.
result = G.Connection((*(G.find_it(queryTo))),(*(G.find_it(queryFrom))));
if(!result)
cout<<"No Connection";
else
cout<<"Degree : "<<result;
return 0;
}
int Graph::Connection(Vertex v1,Vertex v2)
{
// Mark all the vertices as not visited
Vertex s=Vertex("xx");
int i=0;
//list<Vertex>::iterator it;
Vertex *temp=&(*(vertexList.begin()));
while(!temp)
temp->status = false,++temp;
// Create a queue for BFS
list<Vertex> queue;
// Mark the current node as visited and enqueue it
v1.status=true;
queue.push_back(v1);
// it will be used to get all adjacent vertices of a vertex
int depth;
while (!queue.empty())
{
depth=0;
// Dequeue a vertex from queue and print it
s = queue.front();
queue.pop_front();
// Get all adjacent vertices of the dequeued vertex s
// If a adjacent has not been visited, then mark it visited
// and enqueue it
temp=s.adjacencyList.front();
while(temp!=NULL)
{
++depth;
// If this adjacent node is the destination node, then return true
if ((v2.name.compare(temp->name))==0)
{
v2.depth=depth;
return v2.depth;
}
// Else, continue to do BFS
if(temp->status==false)
{
temp->status = true;
queue.push_back(*temp);
}
++temp;
}
}
return 0;
}
I'm going to assume that the degree of connection you are trying to compute is the shortest path distance between nodes (with uniform edge costs). You can use Floyd-Warshall to pre-process the graph and answer queries in O(1) time. It's really simple to implement.
int a[N][N]; /* adjacency matrix where N is max node count */
/* build graph here and init distances between distinct nodes to +INFINITY */
/* n is number of nodes */
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]);
To answer a query (x,y) you print dist[x][y].
Your BFS solution looks unnecessarily complicated. Use a vector<in> g[N] to represent your graph. Add an edge x->y with g[x].push_back(y). BFS would look like:
queue<int> Q;
Q.push(s); /* start node */
for(int i = 0; i < n; i++)
{ dist[i] = INFINITY;
}
dist[s] = 0; /* distance to s is set to 0 */
while(Q.empty() == false)
{ int x = Q.front(); Q.pop();
for(int i = 0; i < g[x].size(); i++)
{ int y = g[x][i];
/* process edge x->y */
if(dist[y] == INFINITY)
{ dist[y] = dist[x] + 1;
Q.push(y);
}
}
}
distance between s and any other node t is dist[s][t].
Your code also crashes in a segmentation fault, if you try to find a connection with degree 1. Given your graph try to find "Harry Krax".
I think the mistake is using a pointer Vertex * temp = temp=s.adjacencyList.front(); and later trying to access the next Vertex by ++temp;.
This is not how std::list in combination with pointers work.
If you want to access the next Vertex with ++temp, than you might want to use iterators std::list<x>::iterator temp.
What you are trying to do works with arrays like int a[N], because the elements of an array are adjacent in memory.
With int * aptr = a. ++aptr says that temp is to move to another location in memory that is the size of one int further away.
std::list<x> does not do this. Here the elements can be scatter at different places in memory. (Simplified) it's value and pointers to the previous and next element are stored.

getting extra edge when removing the edges connected to the source vertex in a graph

last week i posted a code to calculate the shortest path in a graph using Dijkastra algorithm but it was very long and nobody was interesting in reading it completely so i deleted it, and now i am trying to simplify the code by going part by part, the code isn't complete yet, and i will cut part of the code here to focus on the first problem that i am facing so far.
briefly i have a class Graph it is going to be constructed by two other classes a vector of elements are instances of a class Edge , and another vector of elements of class Vertex , every vertex has an id , and every edge has two vertices and weight .
class Graph has a method its name is shortest takes two vertices as arguments the first one for the source of the graph and the second is for the destination.
So far i am trying to eliminate the edges that are connected to the source vertex , but i am getting an extra edge still in the vector edges it is connected to the source while all the other edges related to the source are removed.
to demonstrate the result , i initialized a graph has five vertices vers[0], vers[1], vers[2], vers[3], vers[4], and there are 10 edges connecting those vertices starting from eds[0], eds[1], ....eds[9].
the source vertex is vers[2] is connected by 4 edges , so when applying the method shortest as it is shown in the code below i should get rid of all those 4 edges and end with 6 edges , but the result was that i got rid of 3 edges and i have 7 edges remained, the result is as follows:
Hello, This is a graph
0____1 5
0____3 4
0____4 6
1____3 5
1____4 7
2____4 8
3____4 3
size of edges 7
size of vertices 5
as you can notice , there still an edge connected to the source which is 2 , the problem is in this edge (by the way 8 is the weight of the edge)
2____4 8
there is something wrong in the method shortest and specifically in the for loop , i hope you can help in finding my mistake.
Thanks in advance.
Here is the code
#include<iostream>
#include<vector>
#include <stdlib.h> // for rand()
using namespace std;
const unsigned int N = 5;
class Vertex
{
private:
unsigned int id; // the name of the vertex
public:
unsigned int get_id(){return id;};
void set_id(unsigned int value) {id = value;};
Vertex(unsigned int init_val = 0) :id (init_val){} // constructor
~Vertex() {}; // destructor
};
class Edge
{
private:
Vertex first_vertex; // a vertex on one side of the edge
Vertex second_vertex; // a vertex on the other side of the edge
unsigned int weight; // the value of the edge ( or its weight )
public:
unsigned int get_weight() {return weight;};
void set_weight(unsigned int value) {weight = value;};
Vertex get_ver_1(){return first_vertex;};
Vertex get_ver_2(){return second_vertex;};
void set_first_vertex(Vertex v1) {first_vertex = v1;};
void set_second_vertex(Vertex v2) {second_vertex = v2;};
Edge(const Vertex& vertex_1 = 0, const Vertex& vertex_2 = 0, unsigned int init_weight = 0)
: first_vertex(vertex_1), second_vertex(vertex_2), weight(init_weight)
{
}
~Edge() {} ; // destructor
};
class Graph
{
private:
std::vector<Vertex> vertices;
std::vector<Edge> edges;
public:
Graph(vector<Vertex> ver_vector, vector<Edge> edg_vector)
: vertices(ver_vector), edges(edg_vector){}
~Graph() {}
vector<Vertex> get_vertices(){return vertices;}
vector<Edge> get_edges(){return edges;}
void set_vertices(vector<Vertex> vector_value) {vertices = vector_value;}
void set_edges(vector<Edge> vector_ed_value) {edges = vector_ed_value;}
unsigned int shortest(Vertex src, Vertex dis);
};
unsigned int Graph::shortest(Vertex src, Vertex dis) {
vector<Vertex> ver_out;
vector<Edge> track;
for(unsigned int i = 0; i < edges.size(); ++i)
{
if((edges[i].get_ver_1().get_id() == src.get_id()) || (edges[i].get_ver_2().get_id() == src.get_id()))
{
track.push_back (edges[i]);
if(edges[i].get_ver_1().get_id() == src.get_id())
{ver_out.push_back (edges[i].get_ver_1());}
else
{ver_out.push_back (edges[i].get_ver_2());}
edges.erase(edges.begin() + i ); //****
}
};
}
int main()
{
cout<< "Hello, This is a graph"<< endl;
vector<Vertex> vers(5);
vers[0].set_id(0);
vers[1].set_id(1);
vers[2].set_id(2);
vers[3].set_id(3);
vers[4].set_id(4);
vector<Edge> eds(10);
eds[0].set_first_vertex(vers[0]);
eds[0].set_second_vertex(vers[1]);
eds[0].set_weight(5);
eds[1].set_first_vertex(vers[0]);
eds[1].set_second_vertex(vers[2]);
eds[1].set_weight(9);
eds[2].set_first_vertex(vers[0]);
eds[2].set_second_vertex(vers[3]);
eds[2].set_weight(4);
eds[3].set_first_vertex(vers[0]);
eds[3].set_second_vertex(vers[4]);
eds[3].set_weight(6);
eds[4].set_first_vertex(vers[1]);
eds[4].set_second_vertex(vers[2]);
eds[4].set_weight(2);
eds[5].set_first_vertex(vers[1]);
eds[5].set_second_vertex(vers[3]);
eds[5].set_weight(5);
eds[6].set_first_vertex(vers[1]);
eds[6].set_second_vertex(vers[4]);
eds[6].set_weight(7);
eds[7].set_first_vertex(vers[2]);
eds[7].set_second_vertex(vers[3]);
eds[7].set_weight(1);
eds[8].set_first_vertex(vers[2]);
eds[8].set_second_vertex(vers[4]);
eds[8].set_weight(8);
eds[9].set_first_vertex(vers[3]);
eds[9].set_second_vertex(vers[4]);
eds[9].set_weight(3);
unsigned int path;
Graph graf(vers, eds);
path = graf.shortest(vers[2], vers[4]);
cout<<graf.get_edges()[0].get_ver_1().get_id() <<"____"<<graf.get_edges()[0].get_ver_2().get_id() <<" "<<graf.get_edges()[0].get_weight()<< endl; //test
cout<<graf.get_edges()[1].get_ver_1().get_id() <<"____"<<graf.get_edges()[1].get_ver_2().get_id() <<" "<<graf.get_edges()[1].get_weight()<< endl; //test
cout<<graf.get_edges()[2].get_ver_1().get_id() <<"____"<<graf.get_edges()[2].get_ver_2().get_id() <<" "<<graf.get_edges()[2].get_weight()<< endl; //test
cout<<graf.get_edges()[3].get_ver_1().get_id() <<"____"<<graf.get_edges()[3].get_ver_2().get_id() <<" "<<graf.get_edges()[3].get_weight()<< endl; //test
cout<<graf.get_edges()[4].get_ver_1().get_id() <<"____"<<graf.get_edges()[4].get_ver_2().get_id() <<" "<<graf.get_edges()[4].get_weight()<< endl; //test
cout<<graf.get_edges()[5].get_ver_1().get_id() <<"____"<<graf.get_edges()[5].get_ver_2().get_id() <<" "<<graf.get_edges()[5].get_weight()<< endl; //test
cout<<graf.get_edges()[6].get_ver_1().get_id() <<"____"<<graf.get_edges()[6].get_ver_2().get_id() <<" "<<graf.get_edges()[6].get_weight()<< endl; //test
//cout<<graf.get_edges()[7].get_ver_1().get_id() <<"____"<<graf.get_edges()[7].get_ver_2().get_id() <<" "<<graf.get_edges()[7].get_weight()<< endl; //test
//cout<<graf.get_edges()[8].get_ver_1().get_id() <<"____"<<graf.get_edges()[8].get_ver_2().get_id() <<" "<<graf.get_edges()[8].get_weight()<< endl; //test
//cout<<graf.get_edges()[9].get_ver_1().get_id() <<"____"<<graf.get_edges()[9].get_ver_2().get_id() <<" "<<graf.get_edges()[9].get_weight()<< endl; //test
cout<<"size of edges"<<graf.get_edges().size()<< endl;
cout<<"size of vertices"<<graf.get_vertices().size()<< endl;
return 0;
}
This is because you are effectively skipping some vector elements in your Graph::shortest for loop because you are incrementing i even when you erase current element. Change it to something like this to fix the problem:
for (unsigned int i = 0; i < edges.size();) { // no ++i here
if ((edges[i].get_ver_1().get_id() == src.get_id()) || (edges[i].get_ver_2().get_id() == src.get_id())) {
track.push_back(edges[i]);
if (edges[i].get_ver_1().get_id() == src.get_id()) {
ver_out.push_back(edges[i].get_ver_1());
} else {
ver_out.push_back(edges[i].get_ver_2());
}
edges.erase(edges.begin() + i);
} else {
++i; // increment only if not erasing
}
}
Alternatively as per comment, using iterators:
for (auto i = edges.begin(); i != edges.end();) {
if ((i->get_ver_1().get_id() == src.get_id()) || (i->get_ver_2().get_id() == src.get_id())) {
track.push_back(*i);
if (i->get_ver_1().get_id() == src.get_id()) {
ver_out.push_back(i->get_ver_1());
} else {
ver_out.push_back(i->get_ver_2());
}
i = edges.erase(i);
} else {
i++;
}
}
You are also missing a return statement in that function.

Performance of Dijkstra's algorithm implementation

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;
}