I have a directed graph. Initially, all nodes are assumed to be unvisited and flag is -1 in vector<int>flag. Now we start from a source node & push into stack<int>s and make flag[source]=0 . Now I do DFS traversal & push nodes if(flag[node]==-1)& make flag[node]=0. if all the DFS directed links are visited I pop the element of the stack and mark it flag[s.top()]=1; while pushing if we encounter a node with flag[nodes]==0, the cycle is detected and i do an increment in int final variable;`
you can see in my code, I am storing DFS traversal in a temp vector, which I think is garbage, how can I directly pass these connected nodes directly to check the flag and detect the cycle. currently my code works but fails for larger input. kindly looking for help.
#include<iostream>
#include<vector>
#include<stack>
#include<map>
using namespace std;
int mx=1e5+5;
vector<bool>vist(mx);
vector<vector<int>>Graph(mx);
void dfs(int node,vector<int>&dfs_vec){
vist[node]=true;
dfs_vec.push_back(node);
for(int neigh: Graph[node]){
if(!vist[neigh]){
dfs(neigh,dfs_vec);
}
}
}
//my temp vector is in while loop of main.
int main(){
int num_vertex;int num_edge;
cin>>num_vertex>>num_edge;
int u,v;
for(int i=0;i<num_edge;i++){
cin>>u>>v;
Graph[u].push_back(v);
}
vector<int>flag(num_vertex+1,-1);
stack<int>s;
int source=1;
s.push(source);
flag[source]=0;
int final=0;
while(!s.empty()){
int x=s.top();
vector<int>temp;
dfs(Graph[x][0],temp);
for(auto y:temp){
if(flag[y]==-1){
s.push(y);
flag[y]=0;
}
else if(flag[y]==0){
final++;
}
}
flag[s.top()]=1;
s.pop();
vist.clear();
vist.resize(mx);
}
if(final>0){
std::cout<<"Graph is cyclic";
}
else{
std::cout<<"Graph is not cyclic";
}
}
It is important to minimize the parameters in the signature of a recursive function if you want to handle large datasets. Each call requires the parameters to be kept on the stack, a fairly limited resource.
To minimize the parameters, use a method on a class which stores just one copy of the parameter data as an attribute whenever possible. For DFS, everything except the index of the currently visited node can be moved out of the parameter list.
Here is a straight forward implementation of DFS which I have used successfully on graphs containing hundreds of thousands of vertices.
void cPathFinder::depthRecurse(
int v )
{
visitor(v);
// remember this node has been visited
myPath[v] = 1;
// look for new adjacent nodes
for (int w : adjacent(v))
if (!myPath[w])
{
// search from new node
depthRecurse(w, visitor);
}
}
FYI here is brief discussion of some of the issues to think about when designing a class to implement graph theory algorithms. https://github.com/JamesBremner/PathFinder2/wiki/cGraph-Class-Design
Related
I am trying to detect the cycle in a directed graph. Initially, I have assumed all nodes to be unvisited and have their value as -1 in vector<int>flag. Now we start from a source node and push into stack<int>s and make flag[source]=0 as it is present in stack. Now I will do the DFS traversal and push the nodes if(flag[node]==-1)& make flag[node]=0 in stack starting with that particular source that I pushed in first. if all the DFS directed links are visited I will pop the top element of the stack and mark it flag[s.top()]=1;
while pushing if we encounter a node with flag[nodes]==0, the cycle is detected and i do an increment in int final variable;`
my code works correctly but there is a little issue. for e.g for input with number of vertices and edges =3.
input edges:{1,3},{2,3},{3,2}
input format;
3 3
1 3
2 3
3 2
expected out: "Graph is cyclic"
if i take the only source as 2 then i get the correct answer, but if we have to check it considering each vertex as source so i use a for loop but now i get the wrong output Graph is not cyclic. will kindly request why my approach go wrong.
my code:
#include<iostream>
#include<vector>
#include<stack>
#include<map>
using namespace std;
int mx=1e5+5;
vector<bool>vist(mx);
vector<vector<int>>Graph(mx);
void dfs(int node,vector<int>&dfs_vec){
vist[node]=true;
dfs_vec.push_back(node);
for(int neigh: Graph[node]){
if(!vist[neigh]){
dfs(neigh,dfs_vec);
}
}
}
int main(){
int num_vertex;int num_edge;
cin>>num_vertex>>num_edge;
int u,v;
for(int i=0;i<num_edge;i++){
cin>>u>>v;
Graph[u].push_back(v);
}
int final=0;
for(int source=1;source<=num_vertex;source++){
vector<int>flag(num_vertex+1,-1);
stack<int>s;
s.push(source);
flag[source]=0;
while(!s.empty()){
int x=s.top();
vector<int>temp;
dfs(Graph[x][0],temp);
for(auto y:temp){
if(flag[y]==-1){
s.push(y);
flag[y]=0;
}
else if(flag[y]==0){
final++;
}
}
flag[s.top()]=1;
s.pop();
}
flag.clear();
while(!s.empty()){
s.pop();
}
}
if(final>0){
std::cout<<" Graph is cyclic";
}
else{
std::cout<<" Graph is not cyclic";
}
}
I am writing a program that will detect cycle in a directed graph and will print the nodes that built the cycle. I try use to use a recursive method using C++ by not understanding how to print these nodes after a cycle is detect. Here is my code:
#include <bits/stdc++.h>
using namespace std;
void addedge(list<int>,int ,int );
void cycle_check(list<int>*,int);
// Make a pair between vertex x and vertex y
void addedge(list<int> *ls,int x,int y){
ls[x].push_back(y);
return;
}
void check_cycle_util(list<int> *ls,bool *visit,int curr_node,int &temp){
visit[curr_node]=true;
list<int>::iterator it;
for(it=ls[curr_node].begin();it!=ls[curr_node].end();it++){
if(!visit[*it]){
check_cycle_util(ls,visit,*it,temp);
}
else{
if(temp==0){
temp=1;
cout<<"There is a cycle in the graph\n";
break;
}
}
}
}
//checking the cycles in a graph
void cycle_check(list<int>*ls,int num){
bool *visit=new bool[num];
int temp=0;
for(int i=0;i<num;i++)
visit[i]=false;
for(int i=0;i<num;i++){
if(!visit[i] && temp==0){
check_cycle_util(ls,visit,i,temp);
}
}
}
int main(){
int num;
cout<<"Enter the no. of vertices :";
cin>>num;
list<int> *ls=new list<int>[num];
addedge(ls,0,1);
addedge(ls,2,3);
addedge(ls,3,4);
addedge(ls,4,5);
addedge(ls,1,2);
addedge(ls,1,4);
addedge(ls,3,0);
cycle_check(ls,6);
return 0;
}
I think you could learn the Tarjan Shrink Point Algorithm, it's used to search the strongly connected components.
The main idea is using the same value to mark all the points of a strongly connected component. So the points have the same value are in the same cycle.
The main steps are these:
First, we define two arrays for points, one is the timestamp array, it means the sequence number in the DFS. The other is the low stamp array, it means the min value of the timestamp of the point through DFS, in other words, the value of one point is the min value among timestamp of the point itself and the low stamps of the linked points.
Use DFS to assign the low stamp array, and then all the points which have the same low stamp are in the same cycle.
P.s: Because my Engish is not good so that I can't explain the algorithm very clear. So I recommend you could see another article to learn about this algorithm.
This is an example for using the stack to save path:
the path is a vector defined as a global variable
visit[curr_node]=true;
path.push_back(curr_node);
/* other code */
if(temp==0){
temp=1;
cout<<"There is a cycle in the graph\n";
break;
for(auto i=path.size()-1;path[i]!=curr_node||i==path.size();--i){
cout<<path[i];
}
}
}
path.pop_back();
#include <iostream>
#include <string>
#include <queue>
using namespace std;
void BFS(const string&, const string[], int[][10]);
int main()
{
const int CAP = 10;
string states[CAP] = { "Arizona", "California", "Idaho", "Nevada", "Oregon", "Utah", "Washington" };
string Point;
int matrix[CAP][CAP] =
{
{0,1,0,1,0,1,0},
{1,0,0,1,1,0,0},
{0,0,0,1,1,1,1},
{0,1,1,1,0,0,1},
{1,1,1,1,0,0,0},
{0,0,1,0,1,0,0},
{0,0,1,0,1,0,0}
};
BFS("California", states, matrix);
}
void BFS(const string& Point, const string states[], int matrix[][10])
{
int SPoint = 0;
queue<string> visited;
queue<string> Queue;
string temp = Point;
visited.push(temp);
do
{
for (int i = 0; i < 10; i++)
{
if (states[i] == temp)
{
SPoint = i;
}
}
for (int i = 0; i < 10; i++)
{
if (matrix[SPoint][i] == 1)
{
Queue.push(states[i]);
}
}
visited.push(Queue.front());
Queue.pop();
temp = visited.back();
} while (!Queue.empty());
for (int i = 0; i < 10; i++)
{
cout << visited.front();
visited.pop();
}
}
I'm doing an exercise where I have to make a function that does Breadth-First Search and prints out the visited path. But my function wouldn't print anything. What am I doing wrong here?
Note: The matrix is alphabetical order and represents the connection between states.
My expected output: California Arizona Oregon Nevada Utah Idaho Washington
Exercise description
While I won't offer a complete solution, I can help identify some of the issues the code exhibits.
Major issues
Since you have a cyclic graph, it's important to mark nodes as visited during the BFS else you'll wind up with an infinite loop (which is why nothing gets printed in your current implementation). Your visited queue could be an unordered_set. When nodes are visited, add them to the set and write a conditional to avoid visiting them again.
The adjacency matrix doesn't appear correct. Since it's an undirected graph, I would anticipate that the matrix would be mirrored from top left to bottom right, but it's not. Also, there are no self-edges in the graph yet Nevada appears to have an edge to itself in the matrix.
There's no need to loop over the adjacency matrix--you can index into it by mapping digit indexes and string names appropriately. If you do need to loop, running to 10 is out of bounds on a 7x7 matrix.
Minor issues
There's no sense in arbitrarily restricting the matrix size. Although the assignment enforces this, it's a poor design choice because the code needs to be rewritten any time you want to use a different input graph.
A matrix seems like a slightly awkward data structure here because it introduces an extra layer of indirection to translate strings into integers and back. Although the project doesn't permit it, I'd prefer using a structure like:
std::unordered_map<std::string, std::vector<std::string>> graph({
{"California", {"Oregon", "Nevada", "Arizona"}},
// ... more states ...
});
Ideally, these would be Node objects with neighbor vector members instead of strings.
C++ offers std::vector and std::array which are preferable to C arrays. I assume they haven't been introduced yet in your class or aren't permitted on the assignment, but if you're stuck, you can try writing the code using them, then re-introducing your instructor's constraints after you get it working. If nothing else, it'd be a learning experience.
Avoid using namespace std;.
Reserve uppercase variable names for class names. Objects and primitives should be lowercase.
Pseudocode for BFS
This assumes the preferred data structure above; it's up to you to convert to and from strings and adjacency matrix indexes as needed.
func BFS(string start, unordered_map<string, vector<string>> graph):
vector traversal
queue worklist = {start}
unordered_set visited = {start}
while !worklist.empty():
curr = worklist.pop_front()
traversal.push_back(curr)
for neighbor in graph[curr]:
if neighbor not in visited:
visited.insert(neighbor)
worklist.push(neighbor)
return traversal
Since this is an assignment, I'll leave it at this and let you take another crack at the code. Good luck.
I have been working on a graph implementation for the last few days. All of this is really new to me, and I am stuck on two parts of my implementation. I am implementing a digraph of courses from an input file. From the file, I can determine which courses are prereqs for other courses. I then create a digraph with courses as nodes, and edges connecting courses that are prereqs. I also want to find the total number of nodes and edges, and perform a topological sort on the graph (I will later be adding weights to the edges). Here is my implementation.
Digraph.h
class vertex{
public:
typedef std::pair<int, vertex*> ve;
std::vector<ve> adjacency;
std::string course;
vertex(std::string c){
course = c;
}
};
class Digraph{
public:
void addVertex(std::string&);
void addEdge(std::string& from, std::string& to, int cost);
typedef std::map<std::string, vertex *> vmap;
vmap work;
int getNumVertices();
int getNumEdges();
void getTopoSort();
};
Digraph.cpp
void Digraph::addVertex(std::string& course){
vmap::iterator iter = work.begin();
iter = work.find(course);
if(iter == work.end()){
vertex *v;
v = new vertex(course);
work[course] = v;
return;
}
}
void Digraph::addEdge(std::string& from, std::string& to, int cost){
vertex *f = (work.find(from)->second);
vertex *t = (work.find(to)->second);
std::pair<int, vertex *> edge = std::make_pair(cost, t);
f->adjacency.push_back(edge);
}
Finding the number of nodes was easy just return work.size. I have confirmed this is working properly. I am lost on how I would return the number of edges in my graph. It seems it would be simple, but everything I tried doesn't work. Secondly, I am completely lost on how to perform a topological sort on this graph. Any assistance is appreciated.
A simple way would be to iterate through all vertices in your graph, add up their neighbor counts and then divide by two:
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count / 2;
}
To use the range based for loop, you need to use c++11. With g++ that would be --std=c++11 on the command line.
EDIT:
I just realized you have a directed graph, and you probably want to count one for each direction. In such case: don't divide by two!
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count;
}
First, for the number of edges, it would be simpler to count them directly when you build the graph (just add a counter in your Digraph class and increment it each time you add an edge … )
For the topological sort, first I have a question: your edges are from prereqs to dependant courses ? That is you have a link A -> B if A is a prereq of B ? If this not the case, you need to invert your graph.
You to main algorithm in order to build a topological sort: one based on a simple DFS (http://en.wikipedia.org/wiki/Depth-first_search) and the other relying on in-degrees (http://en.wikipedia.org/wiki/Directed_graph#Indegree_and_outdegree) of your vertices (courses in your case.)
Normally, you need to verify that your graph doesn't contain any cycle, which will normally be the case if your data are coherent.
Let's consider the DFS based algorithm: a DFS traverses each vertices from a given root following edges as they appear. We can easily prove that order of last encounter of a vertex forms a reverse topological order. So, all we need is to push in a stack the current vertex after the calls on its successors.
I made a quick and dirty implementation for you, using C++11 again.
First, add the following to the Digraph class:
typedef std::unordered_set<vertex*> marks_set;
marks_set marks;
typedef std::deque<vertex*> stack;
stack topo;
void dfs(vertex* vcur);
Then here comes the code:
void Digraph::dfs(vertex* vcur) {
marks.insert(vcur);
for (const auto & adj : vcur->adjacency) {
vertex* suc = adj.second;
if (marks.find(suc) == marks.end()) {
this->dfs(suc);
} // you can detect cycle in the else statement
}
topo.push_back(vcur);
}
void Digraph::getTopoSort() {
// It should be a good idea to separate this algorithm from the graph itself
// You probably don't want the inner state of it in your graph,
// but that's your part.
// Be sure marks and topo are empty
marks.clear();
topo.clear();
// Run the DFS on all connected components
for (const auto & v : work) {
if (marks.find(v.second) == marks.end()) {
this->dfs(v.second);
}
}
// Display it
for (const auto v : topo) {
std::cout << v->course << "\n";
}
}
The code compiles but I haven't tested. If for any reasons you have an issue with the recursive algorithm (the function Digraph::dfs), it can be derecursified using a stack containing the parent of the target vertex and the iterator to the current successor, the iterator reach the end of the adjacency list, you can push the parent in the topological sort.
The other algorithm is almost as simple: for each vertices you need to count the number of predecessor (in-degree) which can be done while building the graph. In order to compute the topological sort, you look for the first vertex with a in-degree of 0 (no predecessor), you then decrease the in-degree of all its successors and continue with the next vertex with 0. If the graph has no cycle, there will always be a vertex with a in-degree of 0 (at beginning of course, but also during the algorithm run as you decrease it) until all vertices have been seen. The order of vertices encounter form a topological sort (this is related to the Bellman shortest-path algorithm.)
Note that these 2 algorithms are listed here: http://en.wikipedia.org/wiki/Topological_sorting. The one using in-degree is described in terms of removing edges which we simply simulate by decreasing the in-degree (a far less destructive approach … )
Generally, is creating an undirected graph adt supposed to take a long time?
If I have a graph of 40 nodes, and each node is connected to 20% of the other nodes, my program will stall when it tries to link the nodes together.
The max I can really get up to is 20% density of 20 nodes. My code to link vertexes together looks like this:
while(CalculateDensity()){
LinkRandom();
numLinks++;
}
void LinkRandom(){
int index = rand()%edgeList.size();
int index2 = rand()%edgeList.size();
edgeList.at(index).links.push_back(edgeList.at(index2));
edgeList.at(index2).links.push_back(edgeList.at(index));
}
Is there any way to do this faster?
EDIT: Here is where the data structure declaration:
for(int i=0; i<TOTAL_NODES; i++){
Node *ptr = new Node();
edgeList.push_back(*ptr); //populate edgelist with nodes
}
cout<<"edgelist populated"<<endl;
cout<<"linking nodes..."<<endl;
while(CalculateDensity()){
LinkRandom();
numLinks++;
}
Seems to me that you're copying a growing structure with each push_back.
That could be the cause of slowness.
If you could show the data structure declaration I could try to be more specific.
edit I still miss the Node declaration, nevertheless I would try to change the edgeList to a list of pointers to Node. Then
// hypothetic declaration
class Node {
list<Node*> edgeList;
}
//populate edgelist with nodes
for(int i=0; i<TOTAL_NODES; i++)
edgeList.push_back(new Node());
....
void LinkRandom(){
int index = rand()%edgeList.size();
int index2 = rand()%edgeList.size();
edgeList.at(index)->links.push_back(edgeList.at(index2));
edgeList.at(index2)->links.push_back(edgeList.at(index));
}