I am trying to find the path between two vertices and their distance.
My implementation is the following:
#include <iostream>
#include <list>
#include <string>
#include <vector>
using namespace std;
vector <string> v1 = {"Prague", "Helsinki", "Beijing", "Tokyo", "Jakarta","London", "New York"};
vector <int> w = {};
// A directed graph using
// adjacency list representation
class Graph {
int V; // No. of vertices in graph
list<int>* adj; // Pointer to an array containing adjacency lists
// A recursive function used by printAllPaths()
void printAllPathsUtil(int, int, bool[], int[], int&);
public:
Graph(int V); // Constructor
void addVertex(string name);
void addEdge(int u, int v, int weight);
void printAllPaths(int s, int d);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int u, int v, int weight)
{
adj[u].push_back(v); // Add v to u’s list.
w.push_back(weight);
}
// Prints all paths from 's' to 'd'
void Graph::printAllPaths(int s, int d)
{
// Mark all the vertices as not visited
bool* visited = new bool[V];
// Create an array to store paths
int* path = new int[V];
int path_index = 0; // Initialize path[] as empty
// Initialize all vertices as not visited
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to print all paths
printAllPathsUtil(s, d, visited, path, path_index);
}
// A recursive function to print all paths from 'u' to 'd'.
// visited[] keeps track of vertices in current path.
// path[] stores actual vertices and path_index is current
// index in path[]
void Graph::printAllPathsUtil(int u, int d, bool visited[],
int path[], int& path_index)
{
// Mark the current node and store it in path[]
visited[u] = true;
path[path_index] = u;
path_index++;
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += w[i];
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
}
else // If current vertex is not destination
{
// Recur for all the vertices adjacent to current vertex
list<int>::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
if (!visited[*i])
printAllPathsUtil(*i, d, visited, path, path_index);
}
// Remove current vertex from path[] and mark it as unvisited
path_index--;
visited[u] = false;
}
// Driver program
int main()
{
// Create a graph given in the above diagram
Graph g(7);
g.addEdge(0, 1, 1845);
g.addEdge(0, 5, 1264);
g.addEdge(1, 3, 7815);
g.addEdge(2, 5, 8132);
g.addEdge(2, 6, 11550);
g.addEdge(2, 3, 1303);
g.addEdge(3, 4, 5782);
g.addEdge(3, 6, 10838);
g.addEdge(4, 2, 4616);
g.addEdge(5, 3, 9566);
g.addEdge(6, 5, 5567);
int s = 0, d = 2;
cout << "Following are all different paths from " << v1[s] << " to " << v1[d] << endl;
g.printAllPaths(s, d);
return 0;
}
Obviously this part is wrong:
vector <int> w = {};
w.push_back(weight);
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += w[i];
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
Output is:
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 30606
Prague London Tokyo Jakarta Beijing
Total distance is: 30606
This is wrong (but the path is correct) because of my implementation, it prints out the summation of the overall first 5 weights. But I just did not understand how can I get the weights
How can I get the corresponding weights and add them up?
What I expect:
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 20058
Prague London Tokyo Jakarta Beijing
Total distance is: (There will be some number I have not calculated yet)
There are two main problems here. When you create the edges you do not coupled their cost to them in any way. Also when you traverse them in your algorithm you do not save the cost of traversing the edge, you only save the cities.
Here is a simple solution if you want to keep almost an identical structure. You can accompany the adjecency lists with a list of the costs for each such edge. Son instead of having the w array you can have one such for each noce (city). Then the path array can also be accompanied by another int array with the costs of each step.
Starting with defining and creating the edges it would be:
class Graph {
int V; // No. of vertices in graph
list<int>* adj; // Pointer to an array containing adjacency lists
list<int>* adj_weights; // Pointer to an array containing adjacency lists
...
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
adj_weights = new list<int>[V];
}
void Graph::addEdge(int u, int v, int weight)
{
adj[u].push_back(v); // Add v to u’s list.
adj_weights[u].push_back(weight); // Add the weight of the path as well.
}
Now we have stored the weights and the edges together in a better way, but we still need to use this in the algorithm. Here is an example change of the main functions:
// Prints all paths from 's' to 'd'
void Graph::printAllPaths(int s, int d)
{
// Mark all the vertices as not visited
bool* visited = new bool[V];
// Create an array to store paths
int* path = new int[V];
int* path_costs = new int[V];
int path_index = 0; // Initialize path[] and path_costs[] as empty
// Initialize all vertices as not visited
for (int i = 0; i < V; i++)
visited[i] = false;
// Call the recursive helper function to print all paths
// Note that we let cost = 0 since we don't have to move to the starting city
printAllPathsUtil(s, d, visited, path_costs, path, path_index, 0);
}
// A recursive function to print all paths from 'u' to 'd'.
// visited[] keeps track of vertices in current path.
// path[] stores actual vertices and path_index is current
// index in path[]
void Graph::printAllPathsUtil(int u, int d, bool visited[], int path_costs[],
int path[], int& path_index, int cost)
{
// Mark the current node and store it in path[]
visited[u] = true;
path[path_index] = u;
path_costs[path_index] = cost; // Save cost of this step
path_index++;
int sum = 0;
// If current vertex is same as destination, then print
// current path[]
if (u == d) {
for (int i = 0; i < path_index; i++){
sum += path_costs[i]; // Now add all the costs
cout << v1[path[i]] << " ";
}
cout << endl;
cout << "Total distance is: " << sum;
cout << endl;
}
else // If current vertex is not destination
{
// Recur for all the vertices adjacent to current vertex
// Now we loop over both adj and adj_weights
list<int>::iterator i, j;
for (i = adj[u].begin(), j = adj_weights[u].begin();
i != adj[u].end(); ++i, ++j)
if (!visited[*i])
printAllPathsUtil(*i, d, visited, path_costs, path,
path_index, *j);
}
// Remove current vertex from path[] and mark it as unvisited
path_index--;
visited[u] = false;
}
You can see a full version of the augmented code here https://ideone.com/xGju0y and it gives the following output:
Following are all different paths from Prague to Beijing
Prague Helsinki Tokyo Jakarta Beijing
Total distance is: 20058
Prague London Tokyo Jakarta Beijing
Total distance is: 21228
I hope this helps! I tried to focus on using the same concepts you introduced to not solve things with some new classes or imports. But there are much nicer ways to solve this. One example is to merge the path and path_weights arrays into one array of pairs of ints, and to merge adj and adj_weights into an array of lists of pairs of ints instead of an array of lists of ints.
Related
I have implemented the following C++ Edmonds-Karp algorithm:
#include <iostream>
// Part of Cosmos by OpenGenus Foundation //
#include <limits.h>
#include <string.h>
#include <queue>
using namespace std;
#define V 6
/* Returns true if there is a path from source 's' to sink 't' in
* residual graph. Also fills parent[] to store the path */
bool bfs(int rGraph[V][V], int s, int t, int parent[])
{
// Create a visited array and mark all vertices as not visited
bool visited[V];
memset(visited, 0, sizeof(visited));
// Create a queue, enqueue source vertex and mark source vertex
// as visited
queue <int> q;
q.push(s);
visited[s] = true;
parent[s] = -1;
// Standard BFS Loop
while (!q.empty())
{
int u = q.front();
q.pop();
for (int v = 0; v < V; v++)
if (visited[v] == false && rGraph[u][v] > 0)
{
q.push(v);
parent[v] = u;
visited[v] = true;
}
}
// If we reached sink in BFS starting from source, then return
// true, else false
return visited[t] == true;
}
// Returns tne maximum flow from s to t in the given graph
int fordFulkerson(int graph[V][V], int s, int t)
{
int u, v;
// Create a residual graph and fill the residual graph with
// given capacities in the original graph as residual capacities
// in residual graph
int rGraph[V][V]; // Residual graph where rGraph[i][j] indicates
// residual capacity of edge from i to j (if there
// is an edge. If rGraph[i][j] is 0, then there is not)
for (u = 0; u < V; u++)
for (v = 0; v < V; v++)
rGraph[u][v] = graph[u][v];
int parent[V]; // This array is filled by BFS and to store path
int max_flow = 0; // There is no flow initially
// Augment the flow while tere is path from source to sink
while (bfs(rGraph, s, t, parent))
{
// Find minimum residual capacity of the edges along the
// path filled by BFS. Or we can say find the maximum flow
// through the path found.
int path_flow = INT_MAX;
for (v = t; v != s; v = parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
// update residual capacities of the edges and reverse edges
// along the path
for (v = t; v != s; v = parent[v])
{
u = parent[v];
rGraph[u][v] -= path_flow;
rGraph[v][u] += path_flow;
}
// Add path flow to overall flow
max_flow += path_flow;
}
// Return the overall flow
return max_flow;
}
(source: https://iq.opengenus.org/edmonds-karp-algorithm-for-maximum-flow/)
I would like to save the last BFS of the algorithm, so I can print the minimal cut (which would be {last BFS} {everything else not found in the last BFS})
How do I do that?
I have tried creating a BFS vector every time the bfs function is called, and reset it, but somehow it doesn't seem to work how I imagined:
in bfs function:
bool bfs(int rGraph[V][V], int s, int t, int parent[], vector<int>& search)
{
...
while (!q.empty())
{
int u = q.front();
search.push_back(u);
q.pop();
...
in the fordFulkerson section:
vector<int>tempsearch;
vector<int>search;
while (bfs(rGraph, s, t, parent, search))
{
...
tempsearch.resize(search);
tempsearch = search //this is now a pseudo-code variant
search.resize(0);
}
//at this point tempsearch or search should be the last bfs, no?
return max_flow;
Okay so I found a solution.
We need to have the visited array as a global array (or you can pass it through every single parameter list). This way, every time the array is refreshed, it is also saved in the whole program.
From there, all we have to do is write the output function for the minimal cut:
void printMinCut(){
for(int i = 0; i < visited.size(); i++){
if(visited[i] == true) cout << i;
}
cout << endl;
for(int i = 0; i < visited.size(); i++){
if(visited[i] == false) cout << i;
}
}
And there you have it!
It's my first time using openMP.
Below is given the code so far(which I have not yet been able to parallel,even in a very small part, since I am coming face to face with the error given at the end).
// C++ program to print DFS traversal from a given vertex in a given graph
#include <bits/stdc++.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <omp.h>
using namespace std;
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
// Pointer to an array containing adjacency lists
list<int> *adj;
// A recursive function used by DFS
void DFSUtil(int v, bool visited[]);
public:
Graph(int V); // Constructor
// function to add an edge to graph
void addEdge(int v, int w);
// DFS traversal of the vertices reachable from v
void DFS(int v);
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
}
void Graph::DFSUtil(int v, bool visited[])
{
// Mark the current node as visited and print it
visited[v] = true;
cout << v << " ";
// Recur for all the vertices adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[*i])
DFSUtil(*i, visited);
}
}
// DFS traversal of the vertices reachable from v. It uses recursive DFSUtil().
void Graph::DFS(int v)
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i = 0; i < v; i++)
visited[i] = false;
// Call the recursive helper function to print DFS traversal
DFSUtil(v, visited);
}
// ------------------Drivercode-------------------------------//
int main()
{
//Create a dynamic array to hold the values
vector<int> numbers;
//Create an input file stream
ifstream in("graph_adjacency_list.txt",ios::in);
/*
As long as we haven't reached the end of the file, keep reading entries.
*/
int number; //Variable to hold each number as it is read
//Read number using the extraction (>>) operator
while (in >> number) {
//Add the number to the end of the array
numbers.push_back(number);
}
//Close the file stream
in.close();
/*
Now, the vector<int> object "numbers" contains both the array of numbers,
and its length (the number count from the file).
*/
//Display the numbers
cout << " \n Numbers of our file (graph_adjacency_list.txt):\n";
for (int i=0; i<numbers.size(); i++) {
cout << numbers[i] << ' ';
}
cout << "\n";
int s = numbers.size();
auto start = chrono::steady_clock::now();
// Create a graph given in the above diagram
Graph g(numbers[0]); //<--Takes the number of Vertices , included in the first position of the array(numbers[])
In this part I have the problem :
#pragma omp parallel shared(g) private(i) firstprivate(s)
{
int i =0;
#pragma omp for
for ( i=0; i<s; i=i+2) {
g.addEdge(numbers[i],numbers[i+1]);
}
}
cout << "\n Following is Depth First Traversal"
" (starting from vertex 0): \n";
g.DFS(0);
cout << "\n";
auto end = chrono::steady_clock::now();
auto diff = end - start;
cout << "\n Time taken:" << chrono::duration <double, milli> (diff).count() << " ms" << endl;
cout << "\n";
return 0;
}
When i compile the file through terminal :
ex.--> g++ parallel_DFS.cpp -o parallel_DFS -fopenmp
I take this error:
parallel_DFS.cpp: In function ‘int main()’:
parallel_DFS.cpp:149:44: error: ‘i’ has not been declared
#pragma omp parallel shared(g) private(i) firstprivate(s)
^
and moreover, when i run it on VScode i take:
malloc(): memory corruption
Aborted (core dumped)
Thanks for any help in advance
In the input specification N the number of nodes and M the number of edges are given . So the first simple check is that M should be equal to N-1 otherwise it simply can't be a tree.
What I did next was just a DFS in which I see that whether during the DFS we come across a visited a node again ( different from the parent node, by parent node I mean the node which has called the dfs of the next node adjacent to it ) then it means that we have a cycle and it isn't a tree . But apparently my solution keeps on getting a wrong answer . I am posting the code but only the snippets that are important . I am storing the graph as a adjacency list and I am posting the function isTree() which tests whether it is a tree or not ? What is the correct logic ?
#include <iostream>
#include <list>
using namespace std;
// Graph class represents a directed graph using adjacency list representation
class Graph
{
int V; // No. of vertices
list<int> *adj; // Pointer to an array containing adjacency lists
bool isTreeUtil(int v, bool visited[],int parent);
public:
Graph(int V); // Constructor
void addEdge(int v, int w); // function to add an edge to graph
bool isTree(); // Tells whether the given graph is a tree or not
void printGraph();
};
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V+1];
}
void Graph::addEdge(int v, int w)
{
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
}
bool Graph::isTreeUtil(int v, bool visited[],int parent)
{
//int s_v = v;
visited[v] = true;
list<int>::iterator i;
for(i = adj[v].begin(); i != adj[v].end(); ++i) {
if (!visited[*i])
isTreeUtil(*i,visited,v);
else {
if (*i != parent && visited[*i])
return false;
}
}
return true;
}
bool Graph::isTree() {
bool *visited = new bool[V+1];
for(int i = 1; i < V+1; i++)
visited[i] = false;
visited[1] = true; // marking the first node as visited
for(int i = 1; i < V+1; i++)
visited[i] = false;
int parent = -1; // initially it has no parent
//list<int> :: iterator i;
//for (i = adj[v].begin(); i != adj[v].end(); ++i)
return isTreeUtil(1, visited, parent);
}
void Graph::printGraph() {
for (int i = 1;i <= this->V; i++) {
cout << i << "->";
list<int>::iterator j;
for (j = adj[i].begin(); j != adj[i].end(); ++j) {
cout << *j << "->";
}
cout << "\n";
}
}
int main() {
int N, M;
cin >> N >> M;
Graph G(N);
int v, w;
int m = 0;
while (m < M) {
cin >> v >> w;
G.addEdge(v,w);
m++;
}
if (M != N-1) {
cout << "NO\n";
else if (G.isTree())
cout << "YES\n";
else
cout << "NO\n";
}
I took your code, compiled, and ran it on my machine. When implementing a graph, there are important specs to consider. When you choose to obey a spec, it is generally good practice to enforce that spec in your code.
It is already clear that the graph has 2-way edges, though it does not hurt to specifically mention this.
Allow Duplicate Edges?
Your program allows me to make edge (1,2) and then another edge (1,2) and count it as 2 edges. This makes your conditional M != N-1 an insufficient check. Either disallow duplicate edges or account for them in your algorithm (currently, a duplicate edge will cause your algorithm to return incorrectly).
Self Edges?
Does your graph allow a vertex to have an edge to itself? If so, should the self-path invalidate the tree (perhaps a self-loop is legal because in a tree, every node can access itself)? Currently, self edges also break your algorithm.
To help you, here is my revised implementation of addEdge() that disallows duplicate edges and disallows self-loops. As a bonus it also checks for array bounds ;)
Please note that the additional include, and the change in function signature (it now returns a bool).
#include <algorithm>
bool Graph::addEdge(int v, int w)
{
// sanity check to keep us from seg faulting
if (v < 1 || v > this->V || w < 1 || w > this->V) {
return false;
}
// no self-edges
if (w == v) {
return false;
}
// no duplicate edges allowed either
std::list<int>::iterator findV = std::find(adj[v].begin(), adj[v].end(), w);
std::list<int>::iterator findW = std::find(adj[w].begin(), adj[w].end(), v);
if (findV != adj[v].end() || findW != adj[w].end()) {
return false;
}
adj[v].push_back(w); // Add w to v’s list.
adj[w].push_back(v);
return true;
}
I hope this helps. If this is an assignment, you should review the write-up. They must have specified these cases if your implementation was auto-graded. As #congusbongus mentioned, your algorithm also fails in the case of a disconnected node.
Please note that you also have to revise the main() method in order for my implementation to work. Change this part of the function:
while (m < M) {
cout << "Create Edge from x to y" << endl;
cin >> v >> w;
if (!G.addEdge(v,w)) {
cout << ">>Invalid edge not added" << endl;
} else {
cout << ">>Successfully added edge" << endl;
m++;
}
}
it runs for all the simple test cases I drew on paper but when submitting it fails !
Sounds like some auto-marking system for homework right? If you had access to the exact test cases, then the problem would be obvious. In this case it's probably not available, so we can only speculate.
In my experience, most failures of this kind are due to missed boundary cases. You say you check for number of edges = number of nodes - 1, but have you also considered the following?
All nodes connected
No more than one edge per pair of nodes
That is, is your program prepared to return "NO" for this?
_
/ \
o o---o
Nodes: 3, edges: 2
Currently, in my computer-science course, we are discussing graphs and how to find shortest distance using graphs. I received an assignment about a week ago where the teacher gave us the code for a graph using integers, and we have to adapt it to be able to calculate Levenshtein Distance using a list of words. The problem I'm having though is that I don't understand really how graphs work enough to manipulate one. I've tried googling graphs in c++ but none of the things I found resemble the type of program I was given.
We just finished a unit on linked lists, and I think graphs operate similarly? I understand that each node will point to many other nodes, but in a case where I have 2000 words all pointing to each other, how do I keep track of 2000 pointers per node without declaring that many nodes in my struct? I believe (not 100%) that in the program I was given my teacher used a vector of integer vectors to keep track but I don't know how to implement that.
I'm not asking anyone to fully comment each line as that is an enormous amount of work, but if someone could roughly explain how I would accomplish what I asked above and perhaps read the code and give me a rough understanding of what some sections mean (I'll put comments on some sections I'm specifically having trouble understanding) I would be extremely grateful.
Here is the code we were given:
#include <iostream>
#include <vector>
#include <algorithm> //for max<>
#include <limits>
using namespace std;
typedef vector <int> ivec;
typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement
typedef vector <bool> bvec;
struct graph
{
imatrix edges; //list of attached vertices for each node
int numVertices;
};
//I understand the ostream overloading
ostream & operator << (ostream & stream, ivec &vec)
{
for (int i = 0; i < vec.size(); i++)
{
stream << vec[i] << " ";
}
return stream;
}
ostream & operator << (ostream & stream, graph &g)
{
stream << endl << "numVert = " << g.numVertices << endl;
for (int i = 0; i < g.numVertices; i++)
{
stream << "vertex = " << i+1 << " | edges = " << g.edges[i] << endl;
}
return stream;
}
const int sentinel = -1;
bvec inTree;
ivec distanceNodes;
ivec parents;
void initGraph(graph * g);
void insertEdge(graph * g, int nodeNum, int edgeNum);
void initSearch(graph * g);
void shortestPath(graph * g, int start, int end);
int main()
{
//I understand the main, the two numbers in insertEdge are being hooked together and the two numbers in shortestPath are what we are looking to connect in the shortest way possible
graph g;
initGraph(&g);
insertEdge(&g, 1, 2);
insertEdge(&g, 1, 3);
insertEdge(&g, 2, 1);
insertEdge(&g, 2, 3);
insertEdge(&g, 2, 4);
insertEdge(&g, 3, 1);
insertEdge(&g, 3, 2);
insertEdge(&g, 3, 4);
insertEdge(&g, 4, 2);
insertEdge(&g, 4, 3);
insertEdge(&g, 4, 5);
insertEdge(&g, 5, 4);
insertEdge(&g, 6, 7);
insertEdge(&g, 7, 6);
cout << "The graph is " << g << endl;
shortestPath(&g, 1, 5);
shortestPath(&g, 2, 4);
shortestPath(&g, 5, 2);
shortestPath(&g, 1, 7);
return 0;
}
void initGraph(graph * g)
{
g -> numVertices = 0; //Why set the number of vertices to 0?
}
void insertEdge(graph * g, int nodeNum, int edgeNum)
{
int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other
numVertices = max(1, numVertices);
if (numVertices > g->numVertices)
{
for (int i = g->numVertices; i <= numVertices; i++)
{
ivec nodes;
if (g->edges.size() < i)
{
g -> edges.push_back(nodes);
}
}
g->numVertices = numVertices;
}
g->edges[nodeNum - 1].push_back(edgeNum);
}
void initSearch(graph * g) //I believe this function simply resets the values from a previous search
{
if (g == NULL)
{
return;
}
inTree.clear();
distanceNodes.clear();
parents.clear();
for (int i = 0; i <= g->numVertices; i++)
{
inTree.push_back(false);
distanceNodes.push_back(numeric_limits <int> :: max());
parents.push_back(sentinel);
}
}
void shortestPath(graph * g, int start, int end)
{
//Very confused about how this function works
initSearch(g);
int edge;
int curr; //current node
int dist;
distanceNodes[start] = 0;
curr = start;
while (! inTree[curr])
{
inTree[curr] = true;
ivec edges = g->edges[curr - 1];
for (int i = 0; i < edges.size(); i++)
{
edge = edges[i];
if (distanceNodes[edge] > distanceNodes[curr] + 1)
{
distanceNodes[edge] = distanceNodes[curr] + 1;
parents[edge] = curr;
}
}
curr = 1;
dist = numeric_limits <int> :: max();
for (int i = 1; i <= g->numVertices; i++)
{
if ((!inTree[i]) && (dist > distanceNodes[i]))
{
dist = distanceNodes[i];
curr = i;
}
}
}
ivec path;
if (distanceNodes[end] == numeric_limits <int> :: max()) //is there a numeric_limits <string> :: max?
{
cout << "No way from " << start << " to " << end << endl;
}
else
{
int temp = end;
while (temp != start)
{
path.push_back(temp);
temp = parents[temp];
}
path.push_back(start);
reverse(path.begin(), path.end());
cout << "From " << start << " to " << end << " is " << path << endl;
}
}
If you can help, that would be most welcome as I most likely will have more projects with graphs and I'm struggling due to not understanding them.
Thank you,
Tristan
typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement
Here the graph is represented as Adjacency Matrix. You can also represent a graph using Adjacency List, where each Node would hold a array/linked list of neighboring nodes.
g -> numVertices = 0; //Why set the number of vertices to 0?
It initializes the graph, at startup number of vertices/nodes is zero. When edges and nodes will be inserted using insertEdge method then this number will be updated.
int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other
though you have not posted full code, I think that the maximum value is used to add required number of vertices before inserting an edge.
ivec nodes;
if (g->edges.size() < i)
{
g -> edges.push_back(nodes);
}
above code inserts new vertices. You will probably do integer comparison as here for your version, not string, string is the data of node, not number of node. Still if you need string comparison, C++ already has overloaded operators for this.
About initSearch and shortestPath methods, here the latter finds shortest path between nodes using an algorithm( I don't know which, you can search), and before searching for a shortest path, the former method initializes the values that will be used to search. For example it could set the distances between each pair of node to infinity initially, when a path is found between them, it will be updated.
Some answers:
Q. You asked why numVertices is set to 0 in the following:
void initGraph(graph * g)
{
g -> numVertices = 0; //Why set the number of vertices to 0?
}
A. Look at the declaration of g - it is default initialized:
int main()
{
graph g;
....
}
Now look at the definition of graph - it has no constructor:
struct graph
{
imatrix edges; //list of attached vertices for each node
int numVertices;
};
So edges gets initialized properly by default because vectors have a constructor. But numVertices is a primitive type so it will contain whatever random value happens to be in that memory location - so that means it needs to be manually initialized. Thats why initGraph doesn't need to initialize edges but it does need to initalize numVertices.
Q. You asked how you can find the larger of two std::strings knowing that max() returns the larger of two integers:
int numVertices = max(nodeNum, edgeNum); //Max finds the larger of two numbers I believe? How can this be used with strings, one is not bigger than the other
A. According to http://www.cplusplus.com/reference/algorithm/max/ max uses "The function uses operator< (or comp, if provided) to compare the values." but std::strings can be compared using the < operator so there really is no problem.
Q. You asked about a vector of vectors:
typedef vector <int> ivec;
typedef vector <ivec> imatrix; //A vector of vectors, not how this works or how to implement
A. You can access a vector with [] so if you had a variable called x of imatrix type you could say x[0] which would return an ivec (because that is the type of object stored in an imatrix vector. So if you said x[0][0] that would return the first integer stored in the ivec that is returned by x[0]. To change it to use a string just say:
typedef vector <std::string> ivec;
typedef vector <ivec> imatrix;
You could also rename the variables if you wanted.
You would also need to #include <string>
For example suppose there are 3 nodes A,B,C and A links to B and C, B links to A and C, and C links to B and A. In visual form its like this
C <- A -> B //A links to B & C
A <- B -> C //B links to A & C
B <- C -> A //C links to B & A
Assume the A,B,C are held in an array like so [A,B,C] with index starting at 0. How can I efficiently sort the array [A,B,C] according to the value held by each node.
For example if A holds 4, B holds -2 and C holds -1, then sortGraph([A,B,C]) should return [B,C,A]. Hope its clear. Would it be possible if I can somehow utilize std::sort?
EDIT: Not basic sort algorithm. Let me clarify a bit more. Assume I have a list of Nodes [n0,n1...nm]. Each ni has a left and right neighbor index. For example, n1 left neight is n0 and its right neighbor is n2. I use index to represent the neighbor. If n1 is at index 1, then its left neighbor is at index 0 and its right neighbor is at index 2. If I sort the array, then I need to update the neighbor index as well. I don't want to really implement my own sorting algorithm, any advice on how to proceed?
If I understand the edited question correctly your graph is a circular linked list: each node points to the previous and next nodes, and the "last" node points to the "first" node as its next node.
There's nothing particularly special you need to do the sort that you want. Here are the basic steps I'd use.
Put all the nodes into an array.
Sort the array using any sorting algorithm (e.g. qsort).
Loop through the result and reset the prev/next pointers for each node, taking into account the special cases for the first and last node.
Here is a C++ implementation, hope is useful (it includes several algorithms like dijkstra, kruskal, for sorting it uses depth first search, etc...)
Graph.h
#ifndef __GRAPH_H
#define __GRAPH_H
#include <vector>
#include <stack>
#include <set>
typedef struct __edge_t
{
int v0, v1, w;
__edge_t():v0(-1),v1(-1),w(-1){}
__edge_t(int from, int to, int weight):v0(from),v1(to),w(weight){}
} edge_t;
class Graph
{
public:
Graph(void); // construct a graph with no vertex (and thus no edge)
Graph(int n); // construct a graph with n-vertex, but no edge
Graph(const Graph &graph); // deep copy of a graph, avoid if not necessary
public:
// #destructor
virtual ~Graph(void);
public:
inline int getVertexCount(void) const { return this->numV; }
inline int getEdgeCount(void) const { return this->numE; }
public:
// add an edge
// #param: from [in] - starting point of the edge
// #param: to [in] - finishing point of the edge
// #param: weight[in] - edge weight, only allow positive values
void addEdge(int from, int to, int weight=1);
// get all edges
// #param: edgeList[out] - an array with sufficient size to store the edges
void getAllEdges(edge_t edgeList[]);
public:
// topological sort
// #param: vertexList[out] - vertex order
void sort(int vertexList[]);
// dijkstra's shortest path algorithm
// #param: v[in] - starting vertex
// #param: path[out] - an array of <distance, prev> pair for each vertex
void dijkstra(int v, std::pair<int, int> path[]);
// kruskal's minimum spanning tree algorithm
// #param: graph[out] - the minimum spanning tree result
void kruskal(Graph &graph);
// floyd-warshall shortest distance algorithm
// #param: path[out] - a matrix of <distance, next> pair in C-style
void floydWarshall(std::pair<int, int> path[]);
private:
// resursive depth first search
void sort(int v, std::pair<int, int> timestamp[], std::stack<int> &order);
// find which set the vertex is in, used in kruskal
std::set<int>* findSet(int v, std::set<int> vertexSet[], int n);
// union two sets, used in kruskal
void setUnion(std::set<int>* s0, std::set<int>* s1);
// initialize this graph
void init(int n);
// initialize this graph by copying another
void init(const Graph &graph);
private:
int numV, numE; // number of vertices and edges
std::vector< std::pair<int, int> >* adjList; // adjacency list
};
#endif
Graph.cpp
#include "Graph.h"
#include <algorithm>
#include <map>
Graph::Graph()
:numV(0), numE(0), adjList(0)
{
}
Graph::Graph(int n)
:numV(0), numE(0), adjList(0)
{
this->init(n);
}
Graph::Graph(const Graph &graph)
:numV(0), numE(0), adjList(0)
{
this->init(graph);
}
Graph::~Graph()
{
delete[] this->adjList;
}
void Graph::init(int n)
{
if(this->adjList){
delete[] this->adjList;
}
this->numV = n;
this->numE = 0;
this->adjList = new std::vector< std::pair<int, int> >[n];
}
void Graph::init(const Graph &graph)
{
this->init(graph.numV);
for(int i = 0; i < numV; i++){
this->adjList[i] = graph.adjList[i];
}
}
void Graph::addEdge(int from, int to, int weight)
{
if(weight > 0){
this->adjList[from].push_back( std::make_pair(to, weight) );
this->numE++;
}
}
void Graph::getAllEdges(edge_t edgeList[])
{
int k = 0;
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
// add this edge to edgeList
edgeList[k++] = edge_t(i, this->adjList[i][j].first, this->adjList[i][j].second);
}
}
}
void Graph::sort(int vertexList[])
{
std::pair<int, int>* timestamp = new std::pair<int, int>[this->numV];
std::stack<int> order;
for(int i = 0; i < this->numV; i++){
timestamp[i].first = -1;
timestamp[i].second = -1;
}
for(int v = 0; v < this->numV; v++){
if(timestamp[v].first < 0){
this->sort(v, timestamp, order);
}
}
int i = 0;
while(!order.empty()){
vertexList[i++] = order.top();
order.pop();
}
delete[] timestamp;
return;
}
void Graph::sort(int v, std::pair<int, int> timestamp[], std::stack<int> &order)
{
// discover vertex v
timestamp[v].first = 1;
for(int i = 0; i < this->adjList[v].size(); i++){
int next = this->adjList[v][i].first;
if(timestamp[next].first < 0){
this->sort(next, timestamp, order);
}
}
// finish vertex v
timestamp[v].second = 1;
order.push(v);
return;
}
void Graph::dijkstra(int v, std::pair<int, int> path[])
{
int* q = new int[numV];
int numQ = numV;
for(int i = 0; i < this->numV; i++){
path[i].first = -1; // infinity distance
path[i].second = -1; // no path exists
q[i] = i;
}
// instant reachable to itself
path[v].first = 0;
path[v].second = -1;
while(numQ > 0){
int u = -1; // such node not exists
for(int i = 0; i < numV; i++){
if(q[i] >= 0
&& path[i].first >= 0
&& (u < 0 || path[i].first < path[u].first)){ //
u = i;
}
}
if(u == -1){
// all remaining nodes are unreachible
break;
}
// remove u from Q
q[u] = -1;
numQ--;
for(int i = 0; i < this->adjList[u].size(); i++){
std::pair<int, int>& edge = this->adjList[u][i];
int alt = path[u].first + edge.second;
if(path[edge.first].first < 0 || alt < path[ edge.first ].first){
path[ edge.first ].first = alt;
path[ edge.first ].second = u;
}
}
}
delete[] q;
return;
}
// compare two edges by their weight
bool edgeCmp(edge_t e0, edge_t e1)
{
return e0.w < e1.w;
}
std::set<int>* Graph::findSet(int v, std::set<int> vertexSet[], int n)
{
for(int i = 0; i < n; i++){
if(vertexSet[i].find(v) != vertexSet[i].end()){
return vertexSet+i;
}
}
return 0;
}
void Graph::setUnion(std::set<int>* s0, std::set<int>* s1)
{
if(s1->size() > s0->size()){
std::set<int>* temp = s0;
s0 = s1;
s1 = temp;
}
for(std::set<int>::iterator i = s1->begin(); i != s1->end(); i++){
s0->insert(*i);
}
s1->clear();
return;
}
void Graph::kruskal(Graph &graph)
{
std::vector<edge_t> edgeList;
edgeList.reserve(numE);
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
// add this edge to edgeList
edgeList.push_back( edge_t(i, this->adjList[i][j].first, this->adjList[i][j].second) );
}
}
// sort the list in ascending order
std::sort(edgeList.begin(), edgeList.end(), edgeCmp);
graph.init(numV);
// create disjoint set of the spanning tree constructed so far
std::set<int>* disjoint = new std::set<int>[this->numV];
for(int i = 0; i < numV; i++){
disjoint[i].insert(i);
}
for(int e = 0; e < edgeList.size(); e++){
// consider edgeList[e]
std::set<int>* s0 = this->findSet(edgeList[e].v0, disjoint, numV);
std::set<int>* s1 = this->findSet(edgeList[e].v1, disjoint, numV);
if(s0 == s1){
// adding this edge will make a cycle
continue;
}
// add this edge to MST
graph.addEdge(edgeList[e].v0, edgeList[e].v1, edgeList[e].w);
// union s0 & s1
this->setUnion(s0, s1);
}
delete[] disjoint;
return;
}
#define IDX(i,j) ((i)*numV+(j))
void Graph::floydWarshall(std::pair<int, int> path[])
{
// initialize
for(int i = 0; i < numV; i++){
for(int j = 0; j < numV; j++){
path[IDX(i,j)].first = -1;
path[IDX(i,j)].second = -1;
}
}
for(int i = 0; i < numV; i++){
for(int j = 0; j < this->adjList[i].size(); j++){
path[IDX(i,this->adjList[i][j].first)].first
= this->adjList[i][j].second;
path[IDX(i,this->adjList[i][j].first)].second
= this->adjList[i][j].first;
}
}
// dynamic programming
for(int k = 0; k < numV; k++){
for(int i = 0; i < numV; i++){
for(int j = 0; j < numV; j++){
if(path[IDX(i,k)].first == -1
|| path[IDX(k,j)].first == -1){
// no path exist from i-to-k or from k-to-j
continue;
}
if(path[IDX(i,j)].first == -1
|| path[IDX(i,j)].first > path[IDX(i,k)].first + path[IDX(k,j)].first){
// there is a shorter path from i-to-k, and from k-to-j
path[IDX(i,j)].first = path[IDX(i,k)].first + path[IDX(k,j)].first;
path[IDX(i,j)].second = k;
}
}
}
}
return;
}
If you are looking for sorting algorithms you should just ask google:
http://en.wikipedia.org/wiki/Sorting_algorithm
My personal favourite is the BogoSort coupled with parallel universe theory. The theory is that if you hook a machine up to the program that can destroy the universe, then if the list isn't sorted after one iteration it will destroy the universe. That way all the parallel universes except the one with the list sorted will be destroyed and you have a sorting algorithm with complexity O(1).
The best ....
Create a struct like this:
template<typename Container, typename Comparison = std::less<typename Container::value_type>>
struct SortHelper
{
Container const* container;
size_t org_index;
SortHelper( Container const* c, size_t index ):container(c), org_index(index) {}
bool operator<( SortHelper other ) const
{
return Comparison()( (*c)[org_index], (*other.c)[other.org_index] );
}
};
This lets you resort things however you want.
Now, make a std::vector<SortHelper<blah>>, sort it, and you now have a vector of instructions of where everything ends up going after you sort it.
Apply these instructions (there are a few ways). An easy way would be to reuse container pointer as a bool. Walk the sorted vector of helpers. Move the first entry to where it should go, moving what you found where it should go to where it should go, and repeat until you loop or the entire array is sorted. As you go, clear the container pointers in your helper struct, and check them to make sure you don't move an entry that has already been moved (this lets you detect loops, for example).
Once a loop has occurred, proceed down the vector looking for the next as-yet-not-in-right-place entry (with a non-null container pointer).