Sei sulla pagina 1di 30

Graph Data Structure And Algorithms

Recent Articles on Graph


A Graph is a non-linear data structure consisting of nodes and edges.
The nodes are sometimes also referred to as vertices and the edges are
lines or arcs that connect any two nodes in the graph. More formally a
Graph can be defined as,
A Graph consists of a finite set of vertices(or nodes) and set
of Edges which connect a pair of nodes.

In the above Graph, the set of vertices V = {0,1,2,3,4} and the set of
edges E = {01, 12, 23, 34, 04, 14, 13}.
Graphs are used to solve many real-life problems. Graphs are used to
represent networks. The networks may include paths in a city or
telephone network or circuit network. Graphs are also used in social
networks like linkedIn, Facebook. For example, in Facebook, each person
is represented with a vertex(or node). Each node is a structure and
contains information like person id, name, gender, locale etc.

Graph and its representations


Graph is a data structure that consists of following two components:
1. A finite set of vertices also called as nodes.
2. A finite set of ordered pair of the form (u, v) called as edge. The pair is
ordered because (u, v) is not same as (v, u) in case of a directed
graph(di-graph). The pair of the form (u, v) indicates that there is an
edge from vertex u to vertex v. The edges may contain
weight/value/cost.
Graphs are used to represent many real-life applications: Graphs are
used to represent networks. The networks may include paths in a city or
telephone network or circuit network. Graphs are also used in social
networks like linkedIn, Facebook. For example, in Facebook, each person
is represented with a vertex(or node). Each node is a structure and
contains information like person id, name, gender and locale. See this 
for more applications of graph.
Following is an example of an undirected graph with 5 vertices.

Following two are the most commonly used representations of a graph.


1. Adjacency Matrix
2. Adjacency List
There are other representations also like, Incidence Matrix and
Incidence List. The choice of the graph representation is situation
specific. It totally depends on the type of operations to be performed
and ease of use.
Adjacency Matrix:
Adjacency Matrix is a 2D array of size V x V where V is the number of
vertices in a graph. Let the 2D array be adj[][], a slot adj[i][j] = 1 indicates
that there is an edge from vertex i to vertex j. Adjacency matrix for
undirected graph is always symmetric. Adjacency Matrix is also used to
represent weighted graphs. If adj[i][j] = w, then there is an edge from
vertex i to vertex j with weight w.
The adjacency matrix for the above example graph is:

Pros: Representation is easier to implement and follow. Removing an


edge takes O(1) time. Queries like whether there is an edge from vertex
‘u’ to vertex ‘v’ are efficient and can be done O(1).
Cons: Consumes more space O(V^2). Even if the graph is sparse(contains
less number of edges), it consumes the same space. Adding a vertex is
O(V^2) time.
Please see this for a sample Python implementation of adjacency matrix.

Adjacency List:
An array of lists is used. Size of the array is equal to the number of
vertices. Let the array be array[]. An entry array[i] represents the list of
vertices adjacent to the ith vertex. This representation can also be used
to represent a weighted graph. The weights of edges can be represented
as lists of pairs. Following is adjacency list representation of the above
graph.
// Java Program to demonstrate adjacency list 
// representation of graphs
import java.util.LinkedList;
  
public class GFG 
{
    // A user define class to represent a graph.
    // A graph is an array of adjacency lists.
    // Size of array will be V (number of vertices 
    // in graph)
    static class Graph
    {
        int V;
        LinkedList<Integer> adjListArray[];
          
        // constructor 
        Graph(int V)
        {
            this.V = V;
              
            // define the size of array as 
            // number of vertices
            adjListArray = new LinkedList[V];
              
            // Create a new list for each vertex
            // such that adjacent nodes can be stored
            for(int i = 0; i < V ; i++){
                adjListArray[i] = new LinkedList<>();
            }
        }
    }
      
    // Adds an edge to an undirected graph
    static void addEdge(Graph graph, int src, int dest)
    {
        // Add an edge from src to dest. 
        graph.adjListArray[src].add(dest);
          
        // Since graph is undirected, add an edge from dest
        // to src also
        graph.adjListArray[dest].add(src);
    }
       
    // A utility function to print the adjacency list 
    // representation of graph
    static void printGraph(Graph graph)
    {       
        for(int v = 0; v < graph.V; v++)
        {
            System.out.println("Adjacency list of vertex "+
v);
            System.out.print("head");
            for(Integer pCrawl: graph.adjListArray[v]){
                System.out.print(" -> "+pCrawl);
            }
            System.out.println("\n");
        }
    }
       
    // Driver program to test above functions
    public static void main(String args[])
    {
        // create the graph given in above figure
        int V = 5;
        Graph graph = new Graph(V);
        addEdge(graph, 0, 1);
        addEdge(graph, 0, 4);
        addEdge(graph, 1, 2);
        addEdge(graph, 1, 3);
        addEdge(graph, 1, 4);
        addEdge(graph, 2, 3);
        addEdge(graph, 3, 4);
       
        // print the adjacency list representation of 
        // the above graph
        printGraph(graph);
    }
}
Output:

Adjacency list of vertex 0


head -> 1-> 4
Adjacency list of vertex 1
head -> 0-> 2-> 3-> 4

Adjacency list of vertex 2


head -> 1-> 3

Adjacency list of vertex 3


head -> 1-> 2-> 4

Adjacency list of vertex 4


head -> 0-> 1-> 3
Pros: Saves space O(|V|+|E|) . In the worst case, there can be C(V, 2)
number of edges in a graph thus consuming O(V^2) space. Adding a
vertex is easier.

Cons: Queries like whether there is an edge from vertex u to vertex v are


not efficient and can be done O(V).

Breadth First Search or BFS for a Graph


Breadth First Traversal (or Search) for a graph is similar to Breadth First
Traversal of a tree (See method 2 of this post). The only catch here is,
unlike trees, graphs may contain cycles, so we may come to the same
node again. To avoid processing a node more than once, we use a
boolean visited array. For simplicity, it is assumed that all vertices are
reachable from the starting vertex.
For example, in the following graph, we start traversal from vertex 2.
When we come to vertex 0, we look for all adjacent vertices of it. 2 is
also an adjacent vertex of 0. If we don’t mark visited vertices, then 2 will
be processed again and it will become a non-terminating process. A
Breadth First Traversal of the following graph is 2, 0, 3, 1.
Following are the implementations of simple Breadth First Traversal
from a given source.
The implementation uses adjacency list representation of
graphs. STL‘s list container is used to store lists of adjacent nodes and
queue of nodes needed for BFS traversal.
// Java program to print BFS traversal from a given source
vertex.
// BFS(int s) traverses vertices reachable from s.
import java.io.*;
import java.util.*;
  
// This class represents a directed graph using adjacency list
// representation
class Graph
{
    private int V;   // No. of vertices
    private LinkedList<Integer> adj[]; //Adjacency Lists
  
    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }
  
    // Function to add an edge into the graph
    void addEdge(int v,int w)
    {
        adj[v].add(w);
    }
  
    // prints BFS traversal from a given source s
    void BFS(int s)
    {
        // Mark all the vertices as not visited(By default
        // set as false)
        boolean visited[] = new boolean[V];
  
        // Create a queue for BFS
        LinkedList<Integer> queue = new LinkedList<Integer>();
  
        // Mark the current node as visited and enqueue it
        visited[s]=true;
        queue.add(s);
  
        while (queue.size() != 0)
        {
            // Dequeue a vertex from queue and print it
            s = queue.poll();
            System.out.print(s+" ");
  
            // Get all adjacent vertices of the dequeued
vertex s
            // If a adjacent has not been visited, then mark
it
            // visited and enqueue it
            Iterator<Integer> i = adj[s].listIterator();
            while (i.hasNext())
            {
                int n = i.next();
                if (!visited[n])
                {
                    visited[n] = true;
                    queue.add(n);
                }
            }
        }
    }
  
    // Driver method to
    public static void main(String args[])
    {
        Graph g = new Graph(4);
  
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);
  
        System.out.println("Following is Breadth First
Traversal "+
                           "(starting from vertex 2)");
  
        g.BFS(2);
    }
}
Output:
Following is Breadth First Traversal (starting from vertex 2)
2031
Note that the above code traverses only the vertices reachable from a
given source vertex. All the vertices may not be reachable from a given
vertex (example Disconnected graph). To print all the vertices, we can
modify the BFS function to do traversal starting from all nodes one by
one (Like the DFS modified version) .
Time Complexity: O(V+E) where V is number of vertices in the graph and
E is number of edges in the graph

Depth First Search or DFS for a Graph


Depth First Traversal (or Search) for a graph is similar to Depth First
Traversal of a tree. The only catch here is, unlike trees, graphs may
contain cycles, so we may come to the same node again. To avoid
processing a node more than once, we use a boolean visited array.
For example, in the following graph, we start traversal from vertex 2.
When we come to vertex 0, we look for all adjacent vertices of it. 2 is
also an adjacent vertex of 0. If we don’t mark visited vertices, then 2 will
be processed again and it will become a non-terminating process. A
Depth First Traversal of the following graph is 2, 0, 1, 3.

See this post for all applications of Depth First Traversal.


Following are implementations of simple Depth First Traversal. The C++
implementation uses adjacency list representation of graphs. STL‘s list
container is used to store lists of adjacent nodes.
// Java program to print DFS traversal from a given given
graph
import java.io.*;
import java.util.*;
  
// This class represents a directed graph using adjacency list
// representation
class Graph
{
    private int V;   // No. of vertices
  
    // Array  of lists for Adjacency List Representation
    private LinkedList<Integer> adj[];
  
    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }
  
    //Function to add an edge into the graph
    void addEdge(int v, int w)
    {
        adj[v].add(w);  // Add w to v's list.
    }
  
    // A function used by DFS
    void DFSUtil(int v,boolean visited[])
    {
        // Mark the current node as visited and print it
        visited[v] = true;
        System.out.print(v+" ");
  
        // Recur for all the vertices adjacent to this vertex
        Iterator<Integer> i = adj[v].listIterator();
        while (i.hasNext())
        {
            int n = i.next();
            if (!visited[n])
                DFSUtil(n, visited);
        }
    }
  
    // The function to do DFS traversal. It uses recursive
DFSUtil()
    void DFS(int v)
    {
        // Mark all the vertices as not visited(set as
        // false by default in java)
        boolean visited[] = new boolean[V];
  
        // Call the recursive helper function to print DFS
traversal
        DFSUtil(v, visited);
    }
  
    public static void main(String args[])
    {
        Graph g = new Graph(4);
  
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);
  
        System.out.println("Following is Depth First Traversal
"+
                           "(starting from vertex 2)");
  
        g.DFS(2);
    }
}
Output:
Following is Depth First Traversal (starting from vertex 2)
2013
How to handle disconnected graph?

The above code traverses only the vertices reachable from a given
source vertex. All the vertices may not be reachable from a given vertex
(example Disconnected graph). To do complete DFS traversal of such
graphs, we must call DFSUtil() for every vertex. Also, before calling
DFSUtil(), we should check if it is already printed by some other call of
DFSUtil(). Following implementation does the complete graph traversal
even if the nodes are unreachable. The differences from the above code
are highlighted in the below code.
// Java program to print DFS traversal from a given given
graph
import java.io.*;
import java.util.*;
  
// This class represents a directed graph using adjacency list
// representation
class Graph
{
    private int V;   // No. of vertices
  
    // Array  of lists for Adjacency List Representation
    private LinkedList<Integer> adj[];
  
    // Constructor
    Graph(int v)
    {
        V = v;
        adj = new LinkedList[v];
        for (int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }
  
    //Function to add an edge into the graph
    void addEdge(int v, int w)
    {
        adj[v].add(w);    // Add w to v's list.
    }
  
    // A function used by DFS
    void DFSUtil(int v,boolean visited[])
    {
        // Mark the current node as visited and print it
        visited[v] = true;
        System.out.print(v+" ");
  
        // Recur for all the vertices adjacent to this vertex
        Iterator<Integer> i = adj[v].listIterator();
        while (i.hasNext())
        {
            int n = i.next();
            if (!visited[n])
                DFSUtil(n,visited);
        }
    }
  
    // The function to do DFS traversal. It uses recursive
DFSUtil()
    void DFS()
    {
        // Mark all the vertices as not visited(set as
        // false by default in java)
        boolean visited[] = new boolean[V];
  
        // Call the recursive helper function to print DFS
traversal
        // starting from all vertices one by one
        for (int i=0; i<V; ++i)
            if (visited[i] == false)
                DFSUtil(i, visited);
    }
  
    public static void main(String args[])
    {
        Graph g = new Graph(4);
  
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(1, 2);
        g.addEdge(2, 0);
        g.addEdge(2, 3);
        g.addEdge(3, 3);
  
        System.out.println("Following is Depth First
Traversal");
  
        g.DFS();
    }
}
Output:
Following is Depth First Traversal
0123
Time Complexity: O(V+E) where V is number of vertices in the graph and
E is number of edges in the graph.

Applications of Depth First Search


Depth-first search (DFS) is an algorithm (or technique) for traversing a
graph.
Following are the problems that use DFS as a building block.
1) For an unweighted graph, DFS traversal of the graph produces the
minimum spanning tree and all pair shortest path tree.
2) Detecting cycle in a graph
A graph has cycle if and only if we see a back edge during DFS. So we can
run DFS for the graph and check for back edges. (See this for details)
3) Path Finding
We can specialize the DFS algorithm to find a path between two given
vertices u and z.
i) Call DFS(G, u) with u as the start vertex.
ii) Use a stack S to keep track of the path between the start vertex and
the current vertex.
iii) As soon as destination vertex z is encountered, return the path as the
contents of the stack
See this for details.
4) Topological Sorting
Topological Sorting is mainly used for scheduling jobs from the given
dependencies among jobs. In computer science, applications of this type
arise in instruction scheduling, ordering of formula cell evaluation when
recomputing formula values in spreadsheets, logic synthesis,
determining the order of compilation tasks to perform in makefiles, data
serialization, and resolving symbol dependencies in linkers [2].
5) To test if a graph is bipartite
We can augment either BFS or DFS when we first discover a new vertex,
color it opposited its parents, and for each other edge, check it doesn’t
link two vertices of the same color. The first vertex in any connected
component can be red or black! See this for details.
6) Finding Strongly Connected Components of a graph A directed graph
is called strongly connected if there is a path from each vertex in the
graph to every other vertex. (See this for DFS based algo for finding
Strongly Connected Components)

7) Solving puzzles with only one solution, such as mazes. (DFS can be
adapted to find all solutions to a maze by only including nodes on the
current path in the visited set.)

Applications of Breadth First Traversal


We have earlier discussed Breadth First Traversal Algorithm for Graphs.
We have also discussed Applications of Depth First Traversal. In this
article, applications of Breadth First Search are discussed.
1) Shortest Path and Minimum Spanning Tree for unweighted graph In
an unweighted graph, the shortest path is the path with least number of
edges. With Breadth First, we always reach a vertex from given source
using the minimum number of edges. Also, in case of unweighted
graphs, any spanning tree is Minimum Spanning Tree and we can use
either Depth or Breadth first traversal for finding a spanning tree.
2) Peer to Peer Networks. In Peer to Peer Networks like BitTorrent,
Breadth First Search is used to find all neighbor nodes.

3) Crawlers in Search Engines: Crawlers build index using Breadth First.


The idea is to start from source page and follow all links from source and
keep doing same. Depth First Traversal can also be used for crawlers, but
the advantage with Breadth First Traversal is, depth or levels of the built
tree can be limited.
4) Social Networking Websites: In social networks, we can find people
within a given distance ‘k’ from a person using Breadth First Search till ‘k’
levels.
5) GPS Navigation systems: Breadth First Search is used to find all
neighboring locations.
6) Broadcasting in Network: In networks, a broadcasted packet follows
Breadth First Search to reach all nodes.
7) In Garbage Collection: Breadth First Search is used in copying garbage
collection using Cheney’s algorithm. Refer this and for details. Breadth
First Search is preferred over Depth First Search because of better
locality of reference:
8) Cycle detection in undirected graph: In undirected graphs, either
Breadth First Search or Depth First Search can be used to detect cycle. In
directed graph, only depth first search can be used.
9) Ford–Fulkerson algorithm In Ford-Fulkerson algorithm, we can either
use Breadth First or Depth First Traversal to find the maximum flow.
Breadth First Traversal is preferred as it reduces worst case time
complexity to O(VE2).
10) To test if a graph is Bipartite We can either use Breadth First or
Depth First Traversal.
11) Path Finding We can either use Breadth First or Depth First Traversal
to find if there is a path between two vertices.
12) Finding all nodes within one connected component: We can either
use Breadth First or Depth First Traversal to find all nodes reachable
from a given node.
Many algorithms like Prim’s Minimum Spanning Tree and Dijkstra’s
Single Source Shortest Path use structure similar to Breadth First Search.
There can be many more applications as Breadth First Search is one of
the core algorithms for Graphs.

Graph Cycle :
Detect Cycle in a Directed Graph
Given a directed graph, check whether the graph contains a cycle or not.
Your function should return true if the given graph contains at least one
cycle, else return false. For example, the following graph contains three
cycles 0->2->0, 0->1->2->0 and 3->3, so your function must return true.
Depth First Traversal can be used to detect a cycle in a Graph. DFS for a
connected graph produces a tree. There is a cycle in a graph only if there
is a back edge present in the graph. A back edge is an edge that is from a
node to itself (self-loop) or one of its ancestor in the tree produced by
DFS. In the following graph, there are 3 back edges, marked with a cross
sign. We can observe that these 3 back edges indicate 3 cycles present in
the graph.

For a disconnected graph, we get the DFS forest as output. To detect


cycle, we can check for a cycle in individual trees by checking back
edges.
To detect a back edge, we can keep track of vertices currently in
recursion stack of function for DFS traversal. If we reach a vertex that is
already in the recursion stack, then there is a cycle in the tree. The edge
that connects current vertex to the vertex in the recursion stack is a back
edge. We have used recStack[] array to keep track of vertices in the
recursion stack.
Below image is a dry run of the above approach:

Below is the implementation of the above approach:


// A Java Program to detect cycle in a graph
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
  
class Graph {
      
    private final int V;
    private final List<List<Integer>> adj;
  
    public Graph(int V) 
    {
        this.V = V;
        adj = new ArrayList<>(V);
          
        for (int i = 0; i < V; i++)
            adj.add(new LinkedList<>());
    }
      
    // This function is a variation of DFSUytil() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclicUtil(int i, boolean[] visited,
                                      boolean[] recStack) 
    {
          
        // Mark the current node as visited and
        // part of recursion stack
        if (recStack[i])
            return true;
  
        if (visited[i])
            return false;
              
        visited[i] = true;
  
        recStack[i] = true;
        List<Integer> children = adj.get(i);
          
        for (Integer c: children)
            if (isCyclicUtil(c, visited, recStack))
                return true;
                  
        recStack[i] = false;
  
        return false;
    }
  
    private void addEdge(int source, int dest) {
        adj.get(source).add(dest);
    }
  
    // Returns true if the graph contains a 
    // cycle, else false.
    // This function is a variation of DFS() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclic() 
    {
          
        // Mark all the vertices as not visited and
        // not part of recursion stack
        boolean[] visited = new boolean[V];
        boolean[] recStack = new boolean[V];
          
          
        // Call the recursive helper function to
        // detect cycle in different DFS trees
        for (int i = 0; i < V; i++)
            if (isCyclicUtil(i, visited, recStack))
                return true;
  
        return false;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        Graph graph = new Graph(4);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 0);
        graph.addEdge(2, 3);
        graph.addEdge(3, 3);
          
        if(graph.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't "
                                    + "contain cycle");
    }
}
// A Java Program to detect cycle in a graph
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
  
class Graph {
      
    private final int V;
    private final List<List<Integer>> adj;
  
    public Graph(int V) 
    {
        this.V = V;
        adj = new ArrayList<>(V);
          
        for (int i = 0; i < V; i++)
            adj.add(new LinkedList<>());
    }
      
    // This function is a variation of DFSUytil() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclicUtil(int i, boolean[] visited,
                                      boolean[] recStack) 
    {
          
        // Mark the current node as visited and
        // part of recursion stack
        if (recStack[i])
            return true;
  
        if (visited[i])
            return false;
              
        visited[i] = true;
  
        recStack[i] = true;
        List<Integer> children = adj.get(i);
          
        for (Integer c: children)
            if (isCyclicUtil(c, visited, recStack))
                return true;
                  
        recStack[i] = false;
  
        return false;
    }
  
    private void addEdge(int source, int dest) {
        adj.get(source).add(dest);
    }
  
    // Returns true if the graph contains a 
    // cycle, else false.
    // This function is a variation of DFS() in 
    // https://www.geeksforgeeks.org/archives/18212
    private boolean isCyclic() 
    {
          
        // Mark all the vertices as not visited and
        // not part of recursion stack
        boolean[] visited = new boolean[V];
        boolean[] recStack = new boolean[V];
          
          
        // Call the recursive helper function to
        // detect cycle in different DFS trees
        for (int i = 0; i < V; i++)
            if (isCyclicUtil(i, visited, recStack))
                return true;
  
        return false;
    }
  
    // Driver code
    public static void main(String[] args)
    {
        Graph graph = new Graph(4);
        graph.addEdge(0, 1);
        graph.addEdge(0, 2);
        graph.addEdge(1, 2);
        graph.addEdge(2, 0);
        graph.addEdge(2, 3);
        graph.addEdge(3, 3);
          
        if(graph.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't "
                                    + "contain cycle");
    }
}
Output:
Graph contains cycle
Time Complexity of this method is same as time complexity of DFS
traversal which is O(V+E)

Detect cycle in an undirected graph


.
Given an undirected graph, how to check if there is a cycle in the graph?
For example, the following graph has a cycle 1-0-2-1.

We have discussed cycle detection for directed graph. We have also


discussed a union-find algorithm for cycle detection in undirected
graphs. The time complexity of the union-find algorithm is O(ELogV). Like
directed graphs, we can use DFS to detect cycle in an undirected graph
in O(V+E) time. We do a DFS traversal of the given graph. For every
visited vertex ‘v’, if there is an adjacent ‘u’ such that u is already visited
and u is not parent of v, then there is a cycle in graph. If we don’t find
such an adjacent for any vertex, we say that there is no cycle. The
assumption of this approach is that there are no parallel edges between
any two vertices.
Below image is a dry run of the above approach:
Below is the implementation of the above approach:
// A Java Program to detect cycle in an undirected graph
import java.io.*;
import java.util.*;
  
// This class represents a directed graph using adjacency list
// representation
class Graph
{
    private int V;   // No. of vertices
    private LinkedList<Integer> adj[]; // Adjacency List
Represntation
  
    // Constructor
    Graph(int v) {
        V = v;
        adj = new LinkedList[v];
        for(int i=0; i<v; ++i)
            adj[i] = new LinkedList();
    }
  
    // Function to add an edge into the graph
    void addEdge(int v,int w) {
        adj[v].add(w);
        adj[w].add(v);
    }
  
    // A recursive function that uses visited[] and parent to
detect
    // cycle in subgraph reachable from vertex v.
    Boolean isCyclicUtil(int v, Boolean visited[], int parent)
    {
        // Mark the current node as visited
        visited[v] = true;
        Integer i;
  
        // Recur for all the vertices adjacent to this vertex
        Iterator<Integer> it = adj[v].iterator();
        while (it.hasNext())
        {
            i = it.next();
  
            // If an adjacent is not visited, then recur for
that
            // adjacent
            if (!visited[i])
            {
                if (isCyclicUtil(i, visited, v))
                    return true;
            }
  
            // If an adjacent is visited and not parent of
current
            // vertex, then there is a cycle.
            else if (i != parent)
                return true;
        }
        return false;
    }
  
    // Returns true if the graph contains a cycle, else false.
    Boolean isCyclic()
    {
        // Mark all the vertices as not visited and not part
of
        // recursion stack
        Boolean visited[] = new Boolean[V];
        for (int i = 0; i < V; i++)
            visited[i] = false;
  
        // Call the recursive helper function to detect cycle
in
        // different DFS trees
        for (int u = 0; u < V; u++)
            if (!visited[u]) // Don't recur for u if already
visited
                if (isCyclicUtil(u, visited, -1))
                    return true;
  
        return false;
    }
  
  
    // Driver method to test above methods
    public static void main(String args[])
    {
        // Create a graph given in the above diagram
        Graph g1 = new Graph(5);
        g1.addEdge(1, 0);
        g1.addEdge(0, 2);
        g1.addEdge(2, 1);
        g1.addEdge(0, 3);
        g1.addEdge(3, 4);
        if (g1.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't contains
cycle");
  
        Graph g2 = new Graph(3);
        g2.addEdge(0, 1);
        g2.addEdge(1, 2);
        if (g2.isCyclic())
            System.out.println("Graph contains cycle");
        else
            System.out.println("Graph doesn't contains
cycle");
    }
}
Output:
Graph contains cycle
Graph doesn't contain cycle
Time Complexity: The program does a simple DFS Traversal of graph and
graph is represented using adjacency list. So the time complexity is
O(V+E)
Count all possible paths between two
vertices
Count the total number of ways or paths that exist between two vertices
in a directed graph. These paths doesn’t contain a cycle, the simple
enough reason is that a cylce contain infinite number of paths and hence
they create problem.
Examples:
Input : Count paths between A and E

Output : Total paths between A and E are 4


Explanation: The 4 paths between A and E are:
A -> E
A -> B -> E
A -> C -> E
A -> B -> D -> C -> E

The problem can be solved using backtracking, that is we take a path


and start walking it, if it leads us to the destination vertex then we count
the path and backtrack to take another path. If the path doesn’t leads us
to the destination vertex, we discard the path.
Backtracking for above graph can be shown like this:
The red color vertex is the source vertex and the light-blue color vertex
is destination, rest are either intermediate or discarded paths.

This gives us four paths between source(A) and destination(E) vertex.


Problem Associated with this: Now if we add just one more edge
between C and B, it would make a cycle (B -> D -> C -> B). And hence we
could loop the cycles any number of times to get a new path, and there
would be infinitely many paths because of the cycle.
// Java program to count all paths from a source
// to a destination.
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
  
// This class represents a directed graph using 
// adjacency list representation
  
class Graph {
      
    // No. of vertices
    private int V; 
  
    // Array of lists for
    // Adjacency List 
    // Representation
    private LinkedList<Integer> adj[];
  
    @SuppressWarnings("unchecked")
    Graph(int v) 
    {
        V = v;
        adj = new LinkedList[v];
        for (int i = 0; i < v; ++i)
            adj[i] = new LinkedList<>();
    }
  
    // Method to add an edge into the graph
    void addEdge(int v, int w)
    {
          
        // Add w to v's list.
        adj[v].add(w); 
    }
  
      
    // A recursive method to count
    // all paths from 'u' to 'd'.
    int countPathsUtil(int u, int d,
                    boolean visited[], 
                    int pathCount)
    {
          
        // Mark the current node as
        // visited and print it
        visited[u] = true;
  
        // If current vertex is same as 
        // destination, then increment count
        if (u == d) 
        {
            pathCount++;
        }
              
        // Recur for all the vertices
        // adjacent to this vertex
        else
        {
            Iterator<Integer> i = adj[u].listIterator();
            while (i.hasNext()) 
            {
                int n = i.next();
                if (!visited[n]) 
                {
                    pathCount = countPathsUtil(n, d,
                                            visited,
                                            pathCount);
                }
            }
        }
  
        visited[u] = false;
        return pathCount;
    }
  
    // Returns count of
    // paths from 's' to 'd'
    int countPaths(int s, int d)
    {
          
        // Mark all the vertices
        // as not visited
        boolean visited[] = new boolean[V];
        Arrays.fill(visited, false);
  
        // Call the recursive method
        // to count all paths
        int pathCount = 0;
        pathCount = countPathsUtil(s, d,
                                visited, 
                                pathCount);
        return pathCount;
    }
  
    // Driver Code
    public static void main(String args[]) 
    {
        Graph g = new Graph(4);
        g.addEdge(0, 1);
        g.addEdge(0, 2);
        g.addEdge(0, 3);
        g.addEdge(2, 0);
        g.addEdge(2, 1);
        g.addEdge(1, 3);
  
        int s = 2, d = 3;
        System.out.println(g.countPaths(s, d));
    }
}
  
Output:
3

Potrebbero piacerti anche