Performance of Dijkstra's algorithm implementation - c++

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

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!

My Dijkstra algorithm's not choosing the shortes path

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

A star algorithm finding shortest path but not computing it correctly

Using the following A star visualization as a way to compare path accuracy, I found a large variation between my implementation and this one.
https://qiao.github.io/PathFinding.js/visual/
Path I'm comparing to:
(source: imgsafe.org)
My test paths:
(source: imgsafe.org)
There are times when it seems like the algorithm is checking too few nodes (i.e Test#6). Is this to be expected, or is it not correct?
Important variables in algorithm:
TileMap* m_tileMap;
vector<Tile*> m_openList;
vector<Tile*> m_path;
// Direct mapping of 2D tile map.
// Stores the list type for the same-indexed tile
vector<vector<int>> m_listMap;
Comparator for sorting open list:
struct CompareNodes
{
// sorts lowest F cost to end of vector
bool operator() (Tile* lhs, Tile* rhs)
{
return lhs->getFCost() > rhs->getFCost();
}
};
High level implementation:
vector<Tile*> PathGenerator::generatePath(Tile* startNode, Tile* endNode)
{
setUpListMap();
startNode->setGCost(0);
startNode->setHCost(calculateHCost(startNode, endNode)); // Manhattan (no diagonal). { abs(y2 - y1) + abs(x2 - x1) }
startNode->calculateFCost(); // calculates G+H internally
m_openList.push_back(startNode);
Vector2D startNodePos = startNode->getMapPos();
m_listMap[startNodePos.x][startNodePos.y] = LIST_TYPES::OPEN;
Tile* currentNode;
while (m_openList.empty() == false)
{
currNode = m_openList[m_openList.size() - 1];
m_openList.pop_back();
Vector2D currNodePos = currNode->getMapPos();
m_listMap[currNodePos.x][currNodePos.y] = LIST_TYPES::CLOSED;
if (currNode != endNode)
{
vector<Tile*> neighbours = findNeighbours(currNode);
removeUnnecessaryNodes(&neighbours); // remove walls and closed nodes
computeCosts(&neighbours, currNode, endNode);
addUniqueNodesToOpenList(&neighbours); // ignores duplicates and then sorts open list
}
else
{
m_path = getPath(currNode);
resetLists(); // erases all vectors
}
}
return m_path;
}
void PathGenerator::computeCosts(vector<Tile*>* nodes, Tile* current, Tile* end)
{
int newGCost = current->getGCost() + 1;
for (int i = 0; i < nodes->size(); i++)
{
Tile* node = nodes->at(i);
unsigned int nodeGCost = node->getGCost(); // G cost defaults to max int limit
if (newG < nodeGCost)
{
// set up node costs like above
node->setParentNode(current);
}
}
}
I've added the most important code. If the high level functions don't help to find the source of the issue, let me know and I'll add the implementation for them also.
Help appreciated.
The sorting part seems correct, but since it's a vector this should be very easy for you to verify.
Instead, try using a for-loop as a test-case to make sure you're really get the lowest f-cost node:
Tile* currnode = m_openlist[0];
for (int i = 0; i < m_openList.size() i++)
{
if (m_openList[i]->getFCost() < currnode->getFCost())
currnode = m_openList[i];
}
See if that fixes it. If it does, there's an issue in your sort, but i'm not sure what the issue would be.
Also, in your computeCosts function, you do:
for (int i = 0; i < nodes->size(); i++)
{
Tile* node = nodes->at(i);
//.. other code
}
Since you're using an std::vector, why not make use of its functionality, and use iterators or a range based loop:
// Iterators
for (auto it = nodes->begin(); it != nodes->end(); it++)
{
Tile* node = *it;
//.. other code
}
// Range based loop
for (auto node : *nodes)
{
//.. other code
}

segmentation fault with big array size [duplicate]

so I've been running into a problem where somehow my code is causing segmentation faults before any of my main actually runs. I've never had this happen before and I hardly have a quarter's worth of coding experience so I'm not sure if there's something I'm doing wrong. Everything compiles, at least on my computer, but upon running it my main is never reached.
Context: I'm trying to connect Vertices and Edges in an adjacency matrix and then use Prim's algorithm to build an MST, but that's for later. I built a header file, which originally contained only typdef calls for the structures and the functions. However, I switched the structure definitions to the header file because I was getting memory errors; hence why I think there's an issue with the structs.
graph.h:
//Leland Wong 00000897031
//graph header file
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#ifndef GRAPH_H
#define GRAPH_H
typedef struct vertex
{
double longitude;
double latitude;
char city[30];
int index;
int visited; //0: not visited, 1: visited, 2: visited
struct edge* nexte;
struct vertex* nextv;
double projected;
}VERTEX;
typedef struct edge
{
struct vertex* start;
struct vertex* destination;
double distance;
struct edge* nexte;
}EDGE;
typedef struct graph
{
struct vertex* list[756];
struct edge* matrix[756][756];
}GRAPH;
/*
typedef struct vertex VERTEX;
typedef struct edge EDGE;
typedef struct graph GRAPH;
*/
double findDistance(VERTEX* v1, VERTEX* v2); //compute the distance between two locations
EDGE* connect(VERTEX* v1, VERTEX* v2); //connects two vertices and returns the connecting EDGE
GRAPH primMatrix(GRAPH *g); //connects all vertices using Prim's Algorithm in an adjacency matrix
//void lPrimConnect(VERTEX v); //connects all vertices using Prim's Algorithm in an adjacency list
EDGE* findSmallestEdge(VERTEX v, GRAPH *g); //finds the smallest EDGE connected to v
#endif
graph.c: contains the implementations of all my functions
//functions
//computes the distance between v1 and v2
double findDistance(VERTEX* v1, VERTEX* v2)
{
printf("findDistance");
double long1 = v1->longitude;
double long2 = v2->longitude;
double lat1 = v1->latitude;
double lat2 = v2->latitude;
double distance = 0;
if(long1 < 0)
long1 += 360;
if(long2 < 0)
long2 += 360;
distance = powf((long1-long2), 2) + powf((lat1 - lat2), 2);
distance = sqrt(distance);
return distance;
}
//creates and returns an edge that connects v1 and v2
EDGE* connect(VERTEX* v1, VERTEX* v2)
{
printf("connect");
EDGE *new;
new->start = v1;
new->destination = v2;
new->distance = findDistance(v1, v2);
return new;
}
//finds smallest edge connected to v in GRAPH g
EDGE* findSmallestEdge(VERTEX v, GRAPH *g)
{
printf("findSmallestEdge");
EDGE *tempe;
int i, index;
index = v.index;
//set tempe equal to the first edge connected to v
tempe = g->matrix[index][0];
//find smallest edge connected to v
for(i = 0; i < 756; i++)
{
if(g->matrix[index][i] -> distance < tempe->distance && g->list[index]->visited == 0)
{
tempe = g->matrix[index][i];
}
}
return tempe;
}
//creates an MST out of GRAPH g using Prim's algorithm
GRAPH primMatrix(GRAPH *g)
{
printf("primMatrix");
GRAPH new; // = malloc(sizeof(GRAPH));
EDGE *smallest;
EDGE *tempe;
int i, x;
i = 1;
x = 0;
new.list[0] = g->list[0]; //add root node to MST
g->list[0]->visited = 2;
smallest = findSmallestEdge(*new.list[0], g);
new.matrix[0][smallest->destination->index] = smallest;
//MST will contain all 756 nodes, so run this 755 times to ensure all nodes are reached
while(i < 756)
{
x = 0;
smallest = findSmallestEdge(*new.list[i], g);
//i = number of vertices already reached
while(x < i)
{
tempe = findSmallestEdge(*new.list[x], g);
if(tempe -> distance < smallest -> distance)
{
smallest = tempe;
}
x++;
}
new.list[i] = smallest -> destination;
smallest -> destination -> visited = 2;
new.matrix[smallest->start->index][smallest->destination->index] = smallest;
i++;
}
return new;
}
graphmatrixmain.c: my main function which builds the graphs
#include "graph.h"
int main(int argc, char* argv[])
{
FILE *fp;
static GRAPH g;
char buffer[200];
int i, j;
char city[30];
char *long1;
char *lat1;
if(argc == 1)
{
printf("could not open file\n");
return 0;
}
else
fp = fopen(argv[1], "r");
//read in line of data from txt file, build a new vertex, and insert into list
while(fgets(buffer, 200, fp) != NULL)
{
VERTEX *new = malloc(sizeof(VERTEX));
printf("%s", buffer);
sscanf(buffer, "%s %s %s", city, long1, lat1);
//sscanf(buffer, "%[^\t]\t%[^\t]\t%s", city, long1, lat1);
printf("scanned in data\n");
new->longitude = atof(long1);
new->latitude = atof(lat1);
new->index = i;
g.list[i] = new;
printf("%s: (%lf, %lf)", new->city, new->longitude, new->latitude);
i++;
}
//create EDGE and make connects between every VERTEX in list
for(i = 0; i < 756; i++)
{
for(j = 0; j < 756; j++)
{
g.matrix[i][j] = connect(g.list[i], g.list[j]);
if(j == 0)
{
g.list[i]->nexte = g.matrix[i][j];
}
}
}
return 0;
}
In case its necessary, this is the file i'm reading in from: cities.txt
it contains 756 entries total but as far as the code is concerned size shouldn't be relevant
Shanghai 121.47 31.23
Bombay 72.82 18.96
Karachi 67.01 24.86
Buenos Aires -58.37 -34.61
Delhi 77.21 28.67
Istanbul 29 41.1
Manila 120.97 14.62
Sao Paulo -46.63 -23.53
Moscow 37.62 55.75
I've been running into a problem where somehow my code is causing segmentation faults before any of my main actually runs.
Usually, this means that the data structures that your main tries to place in the automatic storage area overflow the stack. In your situation, it looks like the GRAPH is a suitable suspect to do just that: it has a 2D array with 571536 pointers, which could very well overflow the stack before your main gets a chance to start.
One solution to this problem would be moving the GRAPH into the static area: since you allocate it in the main, it's going to be only one instance of it anyway, so declaring it static should fix the problem:
static GRAPH g;
You might also want to allocate it in the dynamic area using malloc, but in this case it probably does not matter.
Your problem is not "before main" as you state, but in the first few lines of your program. You are not initializing fp, so it could go anywhere. You also have memory errors in your loop with new. You need to copy the value into newly allocated memory.
You cannot see the printfs in your code because the output is buffered and your code crashes before the buffer is flushed. If you put exit(0) just after your printf("error");, you'll see that it works.
I had faced "Segmentation fault occurs before main() execution begins" issue in my C++ code.
Let me try to explain what my issue was and how I could solve it.
A global/static class instance is present in code.
Its constructor is invoked before main() begins.
Inside constructor,in an error handling part, std::cerr is used to display error.
std:cerr was not initialized when constructor was executed.
Even though it says, if #include iostream is there before object is defined then std::cerr is initialized, it was not.
https://en.cppreference.com/w/cpp/io/cerr
If object of std::ios_base::Init is created before constructor, it ensures proper init and deinit of default c++ streams.
why std::cerr was not initialized,
In c++11 objects in iostream are init before other global objects.
But in c++03, it is unspecified.
Use std::ios_base::Init as a private member of class to ensure it is init before stream functions are executed.
Is std::cout guaranteed to be initialized?
One possible reason for segmentation fault before main is the program was mistakenly linked with -shared option. I wasted a lot of time trying to debug it.

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.