Figure -- 02 -- search and path search of figure

Graph search

In many cases, we need to traverse the graph to get some properties of the graph. For example, it is a very common requirement to find out all vertices connected with the specified vertices in the graph, or to determine whether a vertex is connected with the specified vertices.

For graph search, the most classic algorithms are depth first search and breadth first search. Next, we will explain these two search algorithms respectively.

  • Depth first search
  • Breadth first search

Depth first search

Find the child node first, and then the brother node

  • The so-called depth first search means that when searching, if a node has both child nodes and brother nodes, find the child nodes first and then the brother nodes.

    Obviously, because the edge has no direction, if 4 and 5 vertices are connected, then 4 will appear in the adjacent list of 5 and 5 will also appear in the adjacent list of 4. In order not to search the vertices repeatedly, there should be corresponding marks to indicate whether the current vertex has been searched. You can use a Boolean array boolean[V] marked, and the index represents the vertex, The value represents whether the current vertex has been searched. If it has been searched, it is marked as true. If it has not been searched, it is marked as false;

API design:

code:

Figure Graph

package graph;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;


public class Graph {
    //Number of vertices
    private final int V;
    //Number of edges
    private int E;
    //Adjacency table
    private Queue<Integer>[] adj;

    public Graph(int V){
        //Number of initialization vertices
        this.V = V;
        //Number of initialization edges
        this.E = 0;
        //Initialize adjacency table
        this.adj = new Queue[V];

        for (int i = 0; i < adj.length; i++) {
            adj[i] = new ConcurrentLinkedDeque<>();
        }
    }


    //Gets the number of vertices
    public int V(){
        return V;
    }

    //Gets the number of edges
    public int E(){
        return E;
    }

    //Add an edge to the graph v-w
    public void addEdge(int v, int w) {
        //In an undirected graph, the edge has no direction, so the edge can be either an edge from V to w or an edge from w to v. therefore, it is necessary to make w appear in the adjacency table of V and V appear in the adjacency table of W

        adj[v].offer(w);
        adj[w].offer(v);
        //Number of sides + 1
        E++;

    }

    //Gets all vertices adjacent to vertex v
    public Queue<Integer> adj(int v){
        return adj[v];
    }

}

Depth first search - DepthFirstSearch

package graph;

public class DepthFirstSearch {
    //The index represents the vertex, and the value indicates whether the current vertex has been searched
    private boolean[] marked;
    //Record how many vertices are connected to the s vertex
    private int count;

    //Construct a depth first search object, and use depth first search to find all adjacent vertices of s vertex in G graph
    public DepthFirstSearch(Graph G,int s){
        //Initialize marked array
        this.marked = new boolean[G.V()];
        //Initializes the number of vertices communicating with vertex s
        this.count=0;

        dfs(G,s);
    }

    //Use depth first search to find all connected vertices of v vertices in G graph
    private void dfs(Graph G, int v){
        //Identify v vertices as searched
        marked[v] = true;

        for (Integer w : G.adj(v)) {
            //Judge whether the current w vertex has been searched. If not, recursively call the dfs method for depth search
            if (!marked[w]){
                dfs(G,w);
            }

        }

        //Number of connected vertices + 1
        count++;
    }

    //Judge whether the w vertex is connected with the s vertex
    public boolean marked(int w){
        return marked[w];
    }

    //Gets the total number of all vertices connected to vertex s
    public int count(){
        return count;
    }

}

test

public class DepthFirstSearchTest {
    public static void main(String[] args) {

        //Preparing Graph objects
        Graph G = new Graph(13);
        G.addEdge(0,5);
        G.addEdge(0,1);
        G.addEdge(0,2);
        G.addEdge(0,6);
        G.addEdge(5,3);
        G.addEdge(5,4);
        G.addEdge(3,4);
        G.addEdge(4,6);

        G.addEdge(7,8);

        G.addEdge(9,11);
        G.addEdge(9,10);
        G.addEdge(9,12);
        G.addEdge(11,12);



        //Prepare depth first search objects
        DepthFirstSearch search = new DepthFirstSearch(G, 0);

        //Test the number of vertices connected to a vertex
        int count = search.count();
        System.out.println("The number of vertices communicating with the starting point 0 is:"+count);


        //Test whether a vertex is the same as the starting point
        boolean marked1 = search.marked(5);
        System.out.println("Whether vertex 5 and vertex 0 are connected:"+marked1);


        boolean marked2 = search.marked(7);
        System.out.println("Whether vertex 7 and vertex 0 are connected:"+marked2);

    }
}

Breadth first search

First find the sibling node, and then find the child node

  • The so-called depth first search means that when searching, if a node has both child nodes and brother nodes, first find the brother nodes, and then find the child nodes.

API design:

Train of thought analysis:

It is the same as the sequence traversal of binary tree -- breadth first

Tree – 05 - binary tree – 02 - binary search tree (BST) traversal

Implementation steps:

  1. Create a queue to store the nodes of each layer;
  2. Use the loop to pop up a node from the queue:
  3. Get the key of the current node;
  4. If the left child node of the current node is not empty, the left child node is put into the queue
  5. If the right child node of the current node is not empty, the right child node is put into the queue

Create a secondary queue for sorting


code:

package graph;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;

public class BreadthFirstSearch {
    //The index represents the vertex, and the value indicates whether the current vertex has been searched
    private boolean[] marked;
    //Record how many vertices are connected to the s vertex
    private int count;
    //The point used to store the adjacency table to be searched
    private Queue<Integer> waitSearch;

    //Construct a breadth first search object, and use breadth first search to find all adjacent vertices of s vertex in G graph
    public BreadthFirstSearch(Graph G, int s) {
        this.marked = new boolean[G.V()];
        this.count=0;
        this.waitSearch = new ConcurrentLinkedDeque<Integer>();

        bfs(G,s);
    }


    //Use breadth first search to find all adjacent vertices of v vertex in G graph
    private void bfs(Graph graph, int v){
        //Identifies the current vertex v as searched
        marked[v] = true;
        //Let vertex v enter the queue to be searched
        waitSearch.offer(v);
        System.out.print("node"+v+"The breadth traversal order is:"+v);
        //Through the loop, if the queue is not empty, a vertex to be searched will pop up from the queue for search
        while (!waitSearch.isEmpty()){
            //Pop up a vertex to search
            Integer wait = waitSearch.poll();

            //Traversing the adjacency table of wait vertices
            for(Integer w: graph.adj(wait)){
                // The vertex has not been searched yet. Search it
                if(!marked(w)){
                    marked[w] = true;
                    // The node is put on the stack for subsequent acquisition of the child nodes of the node
                    waitSearch.offer(w);
                    //Let the connected vertex + 1;
                    count++;
                    System.out.print( +w);
                }
            }
        }
        System.out.println();
    }

    //Judge whether the w vertex is connected with the s vertex
    public boolean marked(int w) {
        return marked[w];
    }

    //Gets the total number of all vertices connected to vertex s
    public int count() {
        return count;
    }
}


Test:

package graph;

public class BreadthFirstSearchTest {

    public static void main(String[] args) {

        //Preparing Graph objects
        Graph G = new Graph(13);
        G.addEdge(0,5);
        G.addEdge(0,1);
        G.addEdge(0,2);
        G.addEdge(0,6);
        G.addEdge(5,3);
        G.addEdge(5,4);
        G.addEdge(3,4);
        G.addEdge(4,6);

        G.addEdge(7,8);

        G.addEdge(9,11);
        G.addEdge(9,10);
        G.addEdge(9,12);
        G.addEdge(11,12);



        //Prepare breadth first search objects
        BreadthFirstSearch search = new BreadthFirstSearch(G, 0);

        //Test the number of vertices connected to a vertex
        int count = search.count();
        System.out.println("The number of vertices communicating with the starting point 0 is:"+count);


        //Test whether a vertex is the same as the starting point
        boolean marked1 = search.marked(5);
        System.out.println("Whether vertex 5 and vertex 0 are connected:"+marked1);


        boolean marked2 = search.marked(7);
        System.out.println("Whether vertex 7 and vertex 0 are connected:"+marked2);

    }
}

Case - unblocked project continued 1

  • A province investigates the urban traffic conditions and obtains the statistical table of existing urban roads, which lists the cities and towns directly connected by each road. The goal of the provincial government's "unblocked project" is to enable any two cities and towns in the province to realize traffic (but there is not necessarily a direct road connection, as long as they can reach each other indirectly through the road). According to the current road conditions, are city 9 and city 10 connected? Are cities 9 and 8 interlinked?
  • There is a trffic in our test data folder_ Project.txt file, which is the statistical table of Zhengzheng road. The following is the interpretation of the data:

Requirements:

  • There are 20 cities in total. At present, 7 roads have been modified. Do cities 9 and 10 are connected? Are cities 9 and 8 interlinked?

Problem solving ideas:

  1. Create a Graph object to represent the city;
  2. Call AddEdge (0,1), AddEdge (6,9), AddEdge (3,8), AddEdge (5,11), AddEdge (2,12), AddEdge (6,10) and AddEdge (4,8) respectively, indicating that the built roads connect the corresponding cities;
  3. Construct DepthFirstSearch object or BreadthFirstSearch object through Graph object and vertex 9;
  4. By calling the marked(10) and marked(8) methods of the search object, we can get whether the 9 and city are connected with the 10 city and whether the 9 city is connected with the 8 city.

code:

package graph;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Traffic_Project_Test2 {

    public static void main(String[] args) throws Exception{

        //Build a buffered read stream BufferedReader

        BufferedReader br = new BufferedReader(new InputStreamReader(Traffic_Project_Test2.class.getClassLoader().getResourceAsStream("traffic_project.txt")));

        //Read the first row of data 20
        int totalNumber = Integer.parseInt(br.readLine());

        //Build a Graph object
        Graph G = new Graph(totalNumber);

        //Read the second row of data 7
        int roadNumber = Integer.parseInt(br.readLine());
        //Cycle reading for a limited number of times (7) to read the built road
        for (int i = 1;i<=roadNumber;i++){
            String road = br.readLine();//"0 1"
            String[] str = road.split(" ");
            int v = Integer.parseInt(str[0]);
            int w = Integer.parseInt(str[1]);
            //Call the addEdge method of the graph to add an edge to the graph to represent the built road

            G.addEdge(v,w);

        }

        //Build a depth first search object with the starting point set to vertex 9
        DepthFirstSearch search = new DepthFirstSearch(G, 9);

        //Call the marked method to judge whether the 8 vertices and 10 vertices are connected with the starting point 9
        System.out.println("Whether vertex 8 and vertex 9 are connected:"+search.marked(8));
        System.out.println("Whether vertex 10 and vertex 9 are connected:"+search.marked(10));

    }
}

Path lookup

In real life, map is a tool we often use. Usually, we use it for navigation, enter a departure city and a destination city, and we can plan the route. On the planned route, we will pass through many middle cities. Such questions are translated into professional questions:

Requirements:

Is there a path from s vertex to v vertex? If so, find this path.

  • For example, in the above figure, the path from vertex 0 to vertex 4 is marked in red, so we can represent the path as 0-2-3-4.

Find API design

Train of thought analysis:

  • When we implement path search, the most basic operation is to traverse and search the graph. Therefore, our implementation is based on depth first search for the time being. The search process is relatively simple. We added edgeTo [] integer array, which will record the path from each vertex to the starting point s.

If we set the vertex to 0, its search can be represented as the following figure:

According to the result of the final edgeTo, we can easily find the path from the starting point 0 to any vertex;

code:

DepthFirstPaths

import java.util.Stack;

public class DepthFirstPaths {
    //The index represents the vertex, and the value indicates whether the current vertex has been searched
    private boolean[] marked;
    //starting point
    private int s;
    //The index represents the vertex, and the value represents the last vertex on the path from the starting point s to the current vertex
    private int[] edgeTo;

    //Construct the depth first search object, and use the depth first search to find all paths with the starting point of s in the G graph
    public DepthFirstPaths(Graph G, int s){
        //Initialize marked array
        this.marked = new boolean[G.V()];
        //Initialization starting point
        this.s = s;
        //Initialize edgeTo array
        this.edgeTo = new int[G.V()];

        dfs(G,s);
    }

    //Use depth first search to find all adjacent vertices of v vertex in G graph
    private void dfs(Graph G, int v){
        //Represent v as searched
        marked[v] = true;

        //Traverse the adjacency table of vertex v, get each adjacent vertex, and continue the recursive search
        for (Integer w : G.adj(v)) {
            //If the vertex w is not searched, the recursive search continues

            if (!marked[w]){
                edgeTo[w] = v;//The last vertex on the path to vertex w is v
                dfs(G,w);
            }

        }
    }

    //Judge whether there is a path between w vertex and s vertex
    public boolean hasPathTo(int v){
        return marked[v];
    }

    //Find the path from the starting point s to the vertex v (that is, the vertex through which the path passes)
    public Stack<Integer> pathTo(int v){
        if (!hasPathTo(v)){
            return null;
        }

        //Create a stack object and save all vertices in the path
        Stack<Integer> path = new Stack<>();

        //Through the loop, start from vertex v and look forward until you find the starting point
        for (int x = v; x!=s;x = edgeTo[x]){
            path.push(x);
        }

        //Put the starting point s on the stack
        path.push(s);

        return path;
    }



}

Test code


package graph;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;

public class DepthFirstPathsTest {
    public static void main(String[] args) throws Exception{
        //Building a buffered read stream BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(DepthFirstPathsTest.class.getClassLoader().getResourceAsStream("main/resources/road_find.txt")));


        //Read the first row of data 6
        int total = Integer.parseInt(br.readLine());

        //Build a Graph based on the first row of data
        Graph G = new Graph(total);
        //Read the second row of data 8
        int edgeNumbers = Integer.parseInt(br.readLine());
        //Continue to read the two vertices associated with each edge through the loop, and call the addEdge method to add the edge
        for (int i = 1;i<=edgeNumbers;i++){
            String edge = br.readLine();//0 1
            String[] str = edge.split(" ");
            int v = Integer.parseInt(str[0]);
            int w = Integer.parseInt(str[1]);
            G.addEdge(v,w);
        }

        //Build a path to find the object and set the starting point to 0
        graph.DepthFirstPaths paths = new graph.DepthFirstPaths(G, 0);
        //Call pathTo(4), find the path from start point 0 to end point 4, and return to Stack
        Stack<Integer> path = paths.pathTo(4);
        StringBuilder sb = new StringBuilder();
        //Traversal stack object
        for (Integer v : path) {
            sb.append(v+"-");
        }

        sb.deleteCharAt(sb.length()-1);

        System.out.println(sb);
    }
}

Tags: Algorithm data structure linked list

Posted on Thu, 07 Oct 2021 02:02:16 -0400 by mamuni