Graph theory algorithm: reachability and path finding of directed graph

Accessibility of Digraphs

Using the depth first algorithm of digraph, it solves the problem of single point connectivity, and can determine whether other vertices are connected with a given starting point.

package com.algorithms.graph;


/**
 * @author yjw
 * @date 2019/5/20/020
 */
public class DirectedDFS {
    private boolean[] marked;

    public DirectedDFS(DiGraph g, int s) {
        marked = new boolean[g.vertexNum()];
        dfs(g, s);
    }

    /**
     * Find all vertices reachable from all vertices in sources in a digraph
     *
     * @param g
     * @param sources
     */
    public DirectedDFS(DiGraph g, Iterable<Integer> sources) {
        marked = new boolean[g.vertexNum()];
        for (int s : sources) {
            if (!marked[s]) {
                dfs(g, s);
            }
        }
    }

    private void dfs(DiGraph g, int v) {
        marked[v] = true;
        for (int w : g.adj(v)) {
            if (!marked[w]) {
                dfs(g,w);
            }
        }
    }

    /**
     * Is the return vertex v reachable from a known vertex (s or sources)
     * @param v
     * @return
     */
    public boolean marked(int v) {
        return marked[v];
    }

    public static void main(String[] args) {
        DiGraph dg = new DiGraph(6);
        dg.addEdge(0,2,2,0,2,1,2,3,3,2,3,4,3,5);
        DirectedDFS dfs = new DirectedDFS(dg,3);
        for (int v = 0; v < dg.vertexNum(); v++) {
            if (dfs.marked[v]) {
                System.out.print(v + " ");
            }
        }
        System.out.println();

    }
}

We verify that the example digraph is reachable from 3 to all vertices.

The way finding of directed graph

package com.algorithms.graph;

import com.algorithms.stack.Stack;

/**
 * @author yjw
 * @date 2019/5/20/020
 */
public class DepthFirstDirectedPaths {
    private boolean[] marked;  
    private int[] edgeTo;     
    private final int s;      

  
    public DepthFirstDirectedPaths(DiGraph g, int s) {
        marked = new boolean[g.vertexNum()];
        edgeTo = new int[g.vertexNum()];
        this.s = s;
        dfs(g, s);
    }

    private void dfs(DiGraph g, int v) {
        marked[v] = true;
        for (int w : g.adj(v)) {
            if (!marked[w]) {
                edgeTo[w] = v;
                dfs(g, w);
            }
        }
    }

    public boolean hasPathTo(int v) {
        return marked[v];
    }


    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v)) return null;
        Stack<Integer> path = new Stack<>();
        for (int x = v; x != s; x = edgeTo[x]) {
            path.push(x);
        }
        path.push(s);
        return path;
    }

    public static void main(String[] args) {
        DiGraph g = new DiGraph(6);
        g.addEdge(0,2,2,0,2,1,2,3,3,2,3,4,3,5);
        int s = 3;
        DepthFirstDirectedPaths dfs = new DepthFirstDirectedPaths(g, s);

        for (int v = 0; v < g.vertexNum(); v++) {
            if (dfs.hasPathTo(v)) {
                System.out.printf("%d to %d:  ", s, v);
                for (int x : dfs.pathTo(v)) {
                    if (x == s) {
                        System.out.print(x);
                    } else {
                        System.out.print("->" + x);
                    }
                }
                System.out.println();
            }

            else {
                System.out.printf("%d to %d:  not connected\n", s, v);
            }

        }
    }

}

We can use depth first search to answer the question of whether there is a path from a given starting point to a vertex in a digraph (reachability).

The directed graph in our example is constructed above, and the output is as follows:

3 to 0:  3->2->0
3 to 1:  3->2->1
3 to 2:  3->2
3 to 3:  3
3 to 4:  3->4
3 to 5:  3->5

Similarly, the shortest path of a directed graph can be obtained.

package com.algorithms.graph;

import com.algorithms.queue.Queue;
import com.algorithms.stack.Stack;

/**
 * @author yjw
 * @date 2019/5/20/020
 */
public class BreadthFirstDirectedPaths {
    private boolean[] marked;
    /**
     * The closest vertex to the current vertex
     */
    private int[] edgeTo;
    private final int s;

    public BreadthFirstDirectedPaths(DiGraph g, int s) {
        marked = new boolean[g.vertexNum()];
        edgeTo = new int[g.vertexNum()];
        this.s = s;
        bfs(g, s);
    }

    private void bfs(DiGraph g, int s) {
        Queue<Integer> queue = new Queue<>();
        marked[s] = true;
        queue.enqueue(s);
        while (!queue.isEmpty()) {
            int v = queue.dequeue();
            /**
             * Queue all unmarked vertices adjacent to v
             */
            for (int e: g.adj(v)) {
                if (!marked[e]) {
                    marked[e] = true;
                    edgeTo[e] = v;
                    queue.enqueue(e);
                }
            }
        }
    }

    public boolean hasPathTo(int v) {
        return marked[v];
    }

    public Iterable<Integer> pathTo(int v) {
        if (!hasPathTo(v)) {
            return null;
        }
        Stack<Integer> path = new Stack<>();
        /**
         * Find the previous vertex step by step from the end of the path
         */
        for (int x = v; x != s ; x = edgeTo[x]) {
            path.push(x);
        }
        /**
         * Using stack LIFO can print all vertices in the path in sequence
         */
        path.push(s);
        return path;
    }

    public static void main(String[] args) {
        DiGraph g = new DiGraph(6);
        g.addEdge(0,2,2,0,2,1,2,3,3,2,3,4,3,5);
        int s = 0;
        BreadthFirstDirectedPaths bfs = new BreadthFirstDirectedPaths(g, s);

        for (int v = 0; v < g.vertexNum(); v++) {
            if (bfs.hasPathTo(v)) {
                System.out.printf("%d to %d:  ", s, v);
                for (int x : bfs.pathTo(v)) {
                    if (x == s) {
                        System.out.print(x);
                    } else {
                        System.out.print("->" + x);
                    }

                }
                System.out.println();
            }

            else {
                System.out.printf("%d to %d (-):  not connected\n", s, v);
            }

        }
    }
}

Posted on Thu, 07 Nov 2019 12:03:00 -0500 by Sergey Popov