I am trying to implement a simple DFS in C++ with n number of nodes and k number of edges.
For some reason it is getting stuck in an infinite loop:
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define MAXV 1000
void addEdge(vector<int> adj[], int u, int v){
adj[u].pb(v);
adj[v].pb(u);
}
void DFSUtil(int u, vector<int> adj[], vector<int>& visited){
visited[u] = 1;
cout << u << " ";
for(int i = 0;i<adj[u].size();i++){
if(visited[adj[u][i]] == 0){
DFSUtil(u,adj,visited);
}
}
}
void DFS(vector<int> adj[], int N){
vector<int> visited(N, 0);
for(int u = 1;u<N;u++){
if(visited[u] == 0){
DFSUtil(u,adj,visited);
cout << "\n";
}
}
}
int main(){
int n,k,m,i,u,v;
scanf("%d %d",&n,&k);
vector<int> adj[n+1];
for(i = 0;i<k;i++){
scanf("%d %d",&u,&v);
addEdge(adj,u,v);
}
// find connected components
DFS(adj,n+1);
return 0;
}
Could someone point me where am I going wrong with this code?
Sample input to test on:
4 3
1 2
2 3
1 4
After navigating through every steps, finally, I am able to find the bug.
The passed value should have been DFSUtil(adj[u][i],adj,visited); instead of DFSUtil(u,adj,visited); which actually calls the same vertex again and again and hence the infinite loop.
void DFSUtil(int u, vector<int> adj[], vector<int>& visited){
visited[u] = 1;
cout << u << " ";
for(int i = 0;i<adj[u].size();i++){
int to = adj[u][i];
if(visited[to] == 0){
DFSUtil(to, adj, visited);
}
}
}
Related
Hi I am try to implement a graph using adjacency list using following code.
#include<iostream>
#include<list>
#include<vector>
#include<unordered_map>
using namespace std;
class graph{
public:
vector<int> adj[10000];
void insert(int u,int v, bool direction) {
adj[u].push_back(v);
if(direction==1) {
adj[v].push_back(u);
}
}
void print(int n) {
for(int i=0;i<n+1;i++) {
cout<<i<<"->";
for(auto j : adj[i]) {
cout<<j<<",";
}
cout<<endl;
}
}
};
int main( ) {
int n;
cout<<"Enter no of node"<<endl;
cin>>n;
cout<<"enter edges "<<endl;
int m;
cin>>m;
graph g;
for(int i=0;i<m;i++) {
int u, v;
cin>>u>>v;
g.insert(u,v,1);
}
g.print(n);
return 0;
}
But the problem with this code is that it will give correct answer only in the case when my node start from 0 in a continuous manner(0,1,2,3). But when I try to print adjacency list of this graph:
Then it is giving this output:
Can somebody tell me where am I wrong?
The edges you are adding aren't the same as the graph i picture, you are inputting edge 1, 3 instead of edge 1, 5.
It's printing the 0 because you started that for loop from i = 0 and it doesn't print node 5 for the same reason (the loop ends at 4 because you will have i < 4 + 1.
void print(int n) {
//āāā HERE
for(int i=0;i<n+1;i++) {
cout<<i<<"->";
for(auto j : adj[i]) {
cout<<j<<",";
}
cout<<endl;
}
}
Here is how I would change your code:
First, I changed the print() function a little (added the if() to see if the current row is empty and I changed the int n parameter to int maximum which will hold the highest value node so we know when to stop the for).
void print(int maximum)
{
for(int i=0; i<=maximum; i++)
{
if(!adj[i].empty())
{
cout<<i<<"->";
for(auto j : adj[i])
{
cout<<j<<",";
}
cout<<endl;
}
}
}
Then, in main() I added the maximum and aux variables in order to store the aforementioned highest value node. And I also changed the g.print(n) to g.print(maximum).
int main( )
{
int n, maximum = 0, aux;
cout<<"Enter no of node"<<endl;
cin>>n;
cout<<"enter edges "<<endl;
int m;
cin>>m;
graph g;
for(int i=0; i<m; i++)
{
int u, v;
cin>>u>>v;
g.insert(u,v,1);
aux = max(u, v);
maximum = max(maximum, aux);
}
g.print(maximum);
return 0;
}
However, I might not be Terry A. Davis, but I know that if you say you have 4 nodes, those 4 nodes will be 1 2 3 and 4. And I also know that any graph related problem will have nodes starting from 1, therefore every for loop would start from i = 1, or at least that's how I was taught. The way you did it might be correct too, but I am not sure.
This my code for DFS and it should give output like this:
Following is Depth First Traversal:
0 1 3 2 4
but it is giving the output:
Following is Depth First Traversal:
0 2 3 4 1 1 1
I am not visiting the visited element again still it is not working.
#include<bits/stdc++.h>
using namespace std;
void addEdge(vector<int> adj[], int u, int v)
{
adj[u].push_back(v);
adj[v].push_back(u);
}
void DFS(vector<int> adj[], int V, int s)
{
stack<int> st;
bool visited[V];
for(int i=0; i<V;i++)
visited[i] = false;
visited[s] = true;
st.push(s);
while(st.empty()==false)
{
int n=st.top();
st.pop();
visited[n] =true;
cout<<n<<" ";
for(int v:adj[n])
{
if(visited[v]==false)
st.push(v);
}
}
}
int main()
{
int V=5;
vector<int> adj[V];
addEdge(adj,0,1);
addEdge(adj,0,2);
addEdge(adj,2,3);
addEdge(adj,1,3);
addEdge(adj,1,4);
addEdge(adj,3,4);
cout << "Following is Depth First Traversal: "<< endl;
DFS(adj,V,0);
return 0;
}
Unless there is a good reason to use an explicit stack, I would recommend to use recursion(implicit stack). However I am going to fix it least changes to your code.
There are 3 things to fix and I left comments below.
void DFS(vector<int> adj[], int V, int s)
{
stack<int> st;
vector<bool> visited(V, false); // 1. Don't use VLA as it is not standard
// 2. Remove redundant first element visit marking
st.push(s);
while(st.empty()==false)
{
int n=st.top();
st.pop();
// 2. Check if visited since some elements may have added multiple times
// (Some are pushed in the stack many times but not never visited yet)
if (visited[n])
continue;
visited[n] =true;
cout<<n<<" ";
// 3. Reverse the order of iteration
for(auto v = adj[n].rbegin(); v != adj[n].rend(); ++v)
{
if(visited[*v]==false)
st.push(*v);
}
}
}
https://godbolt.org/z/Kz16GT
Adding some more about no. 3 - Actually 0 2 3 4 1 is a valid DFS order too. But it traverses from the reverse order of adj[n] due to the nature of Stack. So iterating reverse way will make the iteration result be 0 1 3 2 4.
I was doing a course on Coursera where they asked to implement DFS to see if two vertices of a graph are connected. I came up with the code and it gives the correct output on my laptop but it gives incorrect output on their grader. I've been breaking my head for days on this problem and have absolutely no idea where I've gone wrong. The code is as follows:
#include<iostream>
#include<vector>
using namespace std;
class Graph
{
public:
vector<int> adj; //adjacency list
void add(int a)
{
adj.push_back(a);
}
void DFS(bool visited[],int n,Graph G[],int v)
{
for(int i=0;i<G[v].adj.size();i++)
{
int vert=G[v].adj[i];
if(visited[vert]==false)
{
visited[vert]=true;
DFS(visited,n,G,vert);
}
}
}
};
int main()
{
int n,m;
cin>>n>>m;//No. of vertices,number of edges
bool visited[n];
for(int i=0;i<n;i++)
visited[n]=false;
Graph G[n];
for(int i=0;i<m;i++)
{
int u,v;
cin>>u>>v; //The vertices joined by two edges
G[u-1].add(v-1);
G[v-1].add(u-1);
}
int k,l;
cin>>k>>l; //The vertices to be checked if they are connected
G[k-1].DFS(visited,n,G,k-1);
if(visited[l-1]==true)
cout<<1;
else
cout<<0;
}
Grader Output:
Failed case #2/16: (Wrong answer)
Input:
4 2
1 2
3 2
1 4
Your output:
1
Correct output:
0
(Time used: 0.00/1.00, memory used: 7839744/536870912.)
If I run the above case in my laptop, it gives the output as 0, the expected answer. I asked the question on the forum and they say that there is some memory leak which I can't identify. Please help.
If you're writing a Graph class, then you should really encapsulate all functionality inside that class. You're not supposed to overwhelm the main function. It makes your code convoluted. Plus you don't have to pass around a lot things in case of a function call. Avoid using using namespace std; as it will lead to namespace collision. To avoid writing std::cout or std::cin, consider using std::cout and using std::cin. I refactored your code and now it gives correct output:
#include <iostream>
#include <cstring>
#include <vector>
using std::cout;
using std::cin;
class Graph
{
public:
static constexpr int MAXN = 100;
std::vector <int> adj[MAXN + 1]; //adjacency list
int visited[Graph::MAXN + 1]; // for 1 based indexing
Graph(){
for(int i = 0 ; i <= MAXN ; ++i) adj[i].clear();
memset(visited, 0, sizeof(visited));
}
void addEdge(bool isDirected, int u, int v)
{
adj[u].push_back(v);
if(!isDirected) adj[v].push_back(u);
}
void takeInput(bool isDirected, int nodes, int edges){
for(int i = 0 ; i < edges ; i++){
int u,v; cin >> u >> v;
addEdge(isDirected, u, v);
}
}
void DFS(int source)
{
visited[source] = 1;
for(int i = 0 ; i < adj[source].size() ; ++i){
int adjNode = adj[source][i];
if(visited[adjNode] == 0){
DFS(adjNode);
}
}
}
bool isConnected(int source, int destination){
DFS(source - 1);
return visited[destination - 1];
}
};
int main()
{
int nodes, edges;
cin >> nodes >> edges;//No. of vertices,number of edges
Graph g;
g.takeInput(false, nodes, edges);
int source, destination;
cin >> source >> destination; //The vertices to be checked if they are connected
cout << g.isConnected(source, destination) << '\n';
return 0;
}
The "error" causing code:
struct Edge
{
int src, dest;
};
// 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
void DFSUtil(int v, bool visited[], int &count); // A function used by DFS
public:
Graph(int V); // Constructor
void addEdge(int v, int w); // function to add an edge to graph
void rmEdge(int v, int w);
int DFS(int v); // DFS traversal of the vertices reachable from 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::rmEdge(int v, int w)
{
cout << "front == " << adj[v].front() << endl;
cout << "back == " << adj[v].back() << endl;
cout << v << " " << w << endl;
cout << "My size is " << adj[v].size() << endl;
adj[v].remove(w);
}
int main()
{
int n, m;
cin >> n >> m;
struct Edge* edges = new Edge[m];
Graph g(n);
for (int i = 0; i < m; ++i)
{
int temp1, temp2;
cin >> temp1 >> temp2;
g.addEdge(temp1, temp2);
edges[i].src = temp1;
edges[i].dest = temp2;
}
for (int i = 0; i < m; ++i)
{
g.rmEdge(edges[i].src, edges[i].dest);
}
return 0;
}
The input I am giving:
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
The output I am getting:
front == 8
back == 1
2 1
My size is 1
Segmentation fault (core dumped)
Now if the size of the list is 1, then how can the front() and back() be different? And even if they are different, why is remove() giving segmentation fault when the value is present in the list (as the back() element)?
An observation:
This code gave Segmentation fault earlier than this code.
Please pardon my horrible debugging approach, but this observation is implying that a cout << endl; is causing output to change in ways it is not supposed to. What is happening here, I am unable to make any sense out of it?
EDIT: I changed the malloc to new and still the same behaviour is persisting.
You're passing a "10" as a "v" to addEdge, trying to access the 11th element. The adj vector has 10 elements, hence you're writing somewhere in the memory where you should not.
In any case, manual allocation and deallocation is recipe for trouble, consider using stl vectors.
//DFS of connected and disconnected graphs
#include <iostream>
#include <vector>
using namespace std;
class Graph {
int V;
vector<int> *adj;
void DFSutil(int v, bool visited[]);
public:
Graph(int V);
void addEdge(int v, int w);
void DFS();
//void DFS(int v); for connected
};
Graph::Graph(int V) {
this->V = V;
adj = new vector<int>[V];
}
void Graph::addEdge(int v, int w) {
adj[v].push_back(w);
}
void Graph::DFSutil(int v, bool visited[]) {
visited[v] = true;
cout << v << " ";
vector<int>::iterator i;
for (i=adj[v].begin(); i!= adj[v].end(); ++i)
if(!visited[*i])
DFSutil(*i,visited);
}
void Graph::DFS() {
bool* visited = new bool[V];
for (int i=0; i<V; ++i) {
visited[i] = false;
}
for (int i=0; i<V; ++i) {
if (visited[i] == false)
DFSutil(i, visited);
}
// simply DFSutil(v,visited) if you are sure every vertex is reachable from any vertex, i.e., graph is connected
}
int main()
{
// Create a graph given in the above diagram
int N, E, N1, N2;
cin >> N >> E;
Graph g(N);
while(E--) {
cin >> N1 >> N2;
cout << N1 << " " << N2 <<" added" << endl;
g.addEdge(N1, N2);
}
cout << "Following is Depth First Traversal\n";
g.DFS();
//g.DFS(2) for connected
return 0;
}
The above is a simple implementation for DFS which should work well for connected and disconnected graphs including trees.
For the input (connected graph) -
4 6
0 1
0 2
1 2
2 0
2 3
3 3
It shows success, but for input (tree) -
3 2
1 2
2 3
It shows runtime error on Ideone.
Am I missing something here?
The problem is not in your code, but in your sample:
3 2
1 2
2 3
Here you mean a graph with 3 vertices (numbered from 0 to 2 as it's obvious from your first example and from your code). But the edges added connect vertices 1 and 2 and 2 and 3. There's not an error when you add an edge from 2 to 3 (yes, that's a logic error, consider adding an assertion here, but the crash does not happen since this edge is added to the adjacency vector of vertex 2). But in DFS, you see this edge when launched from the vertex 2, and try to check whether or not the vertex 3 was visited, accessing the element out of the array bounds, which is UB.
This may be seen in 2 minutes in debugger, why don't you debug your code prior to posting questions?