Depth-first search & breadth-first search

Adjacency list

Adjacency table depth-first search

If we have the following undirected graph

figure 1

If we want to be depth-first traversal, then, in fact, more than one case, for example, 01257643

The following describes the use of temporary connection table method be traversed, so long generally adjacency table below:

Thinking: Referring to FIG we can see two vertical, adjacent to the left half of the table is a linked list array, a total of seven positions 0-6, corresponds to a position on each chain, as in the following positions 0, indicating that it is the first nodes, the list on the right of node1 and node3 respectively adjacent node 0 node of their position,

Adjacency list

Depth-first is a road go black, go elsewhere back to back, so usually use recursion;

Ideas:

For example, we start from node0, then you can go node1 can also go node3, pick a node1, and then start to go down from node1, node2, or we can go to the map view node4 --- combined with such moves, translate what is follows

  1. Print this node value
  2. Mark the current node is visited
  3. Traversing the current node adjacency list
    1. If the adjacent table of elements have been visited, skip
    2. If the adjacent node table not been accessed, the process is repeated 123

Package adjacency table

public class Graph {
    private int size;
    // 链表数组实现邻接表
    private LinkedList<Integer> list[];

    public Graph(int size) {
        this.size = size;
        list = new LinkedList[size];
        for (int i = 0; i < size; i++) {
            list[i] = new LinkedList<>();
        }
    }

    /**
     * 接收两个顶点 , 添加边
     *
     * @param a
     * @param b
     */
    public void addEdge(int a, int b) {
        list[a].add(b);
        list[b].add(a);
    }

      public static void main(String[] args) {
        Graph graph = new Graph(8);
        graph.addEdge(0, 1);
        graph.addEdge(0, 3);
        graph.addEdge(1, 2);
        graph.addEdge(1, 4);
        graph.addEdge(2, 5);
        graph.addEdge(4, 5);
        graph.addEdge(4, 6);
        graph.addEdge(5, 7);
        graph.addEdge(6, 7);

        graph.dfs(0);
      }
}

Depth-first traversal

    public void dfs(int start) {
        boolean[] visited = new boolean[this.size];
        dodfs(start, this.list, visited);
    }

    /**
     * 递归深度搜索
     *
     * @param list
     * @param visited
     */
    private void dodfs(int start, LinkedList<Integer>[] list, boolean[] visited) {
        // 检查当前节点有没有被访问过
        if (visited[start]) {
            return;
        }
        System.out.println(start);
        visited[start] = true;
        for (int i = 0; i < this.list[start].size(); i++) {
            int node = this.list[start].get(i);
            dodfs(node, list, visited);
        }
    }

Breadth-first search adjacency list

figure 1

Or to see the FIG., The breadth-first traversal, then, is traversed by layer, so in general, such as 01324567

In fact, this is the case then you can not use a recursive design function, in fact, I should be able to judge them, recursive, then ran easily to the side of the chart, while traversing the bin may be traversed before the other side, unfortunately, was asked Mongolia ...

Breadth-first ideas:

Using a queue to assist complete, the following ideas

  1. The current node is added to queue
  2. Print the value of the current node
  3. Traversing the nodes adjacent to the current node table
    1. If the node had been visited, skip, does not deal with him
    2. 如果当前节点没有被访问过, 并且队列中现在没有这个节点, 就将它添加进队列
  4. 移除并得到 头节点
  5. 将头结点在辅助数组visited中的标记 置为 true , 标识这个节点被访问过了
  6. 更新现当前队列头位置的node, 在邻接表中的位置

代码如下:

 /**
     * 广度优先搜索
     *
     * @param start
     */
    public void bfs(int start) {
        boolean[] visited = new boolean[this.size];
        dobfs(start, visited, this.list);

    }

    /**
     * 广度优先搜索
     *
     * @param start
     * @param visited
     * @param list
     */
    private void dobfs(int start, boolean[] visited, LinkedList<Integer>[] list) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(start);
        while (queue.size() > 0) {
            // 打印当前的节点
            System.out.println(queue.peek());
            for (int i = 0; i < this.list[start].size(); i++) {
                if (visited[this.list[start].get(i)]) {
                    continue;
                }
                /**
                 *  解决下面情况
                 *     1
                 *    / \
                 *   2   3
                 *    \ /
                 *     5
                 */
                if (!queue.contains(this.list[start].get(i))){
                    queue.add(this.list[start].get(i));
                }
            }

            // 移除头结点
            Integer poll = queue.poll();
            visited[poll] = true;
            // 更新start值
            if (queue.size() > 0) {
                start = queue.peek();
            }
        }
    }

临接数组

临接数组的深度优先搜索

什么是临接数组?

如下图:

figure 2

转换成临接矩阵长下面这样, 很清晰的可以看出, 左下角和右上角是对称的, 怎么解读下面的图形呢?

它其实就是一个二维数组 int [权重][X] 二维数组可以理解成数组嵌套数组, 因此前面的 X 其实对应的下图中的一行, 即 一个小数组

  • 最左边的 纵向坐标是 0 1 2 3 分别表示当前节点的 权值
  • 下图中的每一行都代表着前面的权值对应的 临接点的数量
  • 0 表示不是它的临接点 , 1 表示是临接点

Pro access matrix

创建邻接表的代码如下

public class Graph1 {
    //顶点数
    private int numVertexes;
    // 边数
    private int numEdges;
    // 记录顶点
    int[] vertexes;
    // 二维数组图
    private int[][] points;
    // 用于标记某个点是否被访问过的 辅助数组
    private boolean[] visited;

    private Scanner scanner = new Scanner(System.in);

    public Graph1(int numVertexes, int numEdges) {
        this.numEdges = numEdges;
        this.numVertexes = numVertexes;
        // 初始化邻接矩阵
        this.points = new int[numVertexes][numVertexes];
        // 初始化存放顶点的数组
        this.vertexes = new int[numVertexes];
        // 标记已经访问过的数组
        this.visited = new boolean[this.numVertexes];
    }

    // 构建无向图
    public int[][] buildGraph() {
        System.out.println("请输入顶点的个数");

        this.numVertexes = scanner.nextInt();
        System.out.println("请输入边数");
        this.numEdges = scanner.nextInt();
        // 构建临接矩阵
        for (int i = 0; i < this.numEdges; i++) {
            System.out.println("请输入点(i,j)的 i 值");
            int i1 = scanner.nextInt();
            System.out.println("请输入点(i,j)的 j 值");
            int j1 = scanner.nextInt();
            this.points[i1][j1] = 1;
            this.points[j1][i1] = 1;
        }
        return this.points;
    }

深度优先搜索

思路: 深度优先依然使用递归算法

  1. 打印当前节点的值
  2. 标记当前节点已经被访问过了
  3. 遍历当前节点的临接矩阵
    1. 如果发现遍历的节点为0 , 不处理, 继续遍历
    2. 如果发现遍历的节点为1 , 但是已经被标记访问过了, 不处理, 继续遍历
    3. 如果发现节点值为1 , 且没有被访问过, 递归重复123步骤
  /**
     * 深度搜索
     *
     * @param arr   待搜索的数组
     * @param value 顶点上的值
     */
    public void dfs(int[][] arr, int value) {
        System.out.println(value);
        visited[value] = true;
        for (int i = 0; i < arr.length; i++) {
            if (arr[value][i] != 0 && !visited[i]) {
                dfs(arr, i);
            }
        }
    }

临接数组的广度优先搜索

思路: 广度优先遍历临接矩阵和上面说的邻接表大致相同, 同样需要一个辅助队列

  1. 将头结点添加到队列中
  2. 打印头结点的值
  3. 遍历头结点的临接矩阵
    1. 如果发现遍历的节点为0 , 不处理, 继续遍历
    2. 如果发现遍历的节点为1 , 但是已经被标记访问过了, 不处理, 继续遍历
    3. 如果发现节点值为1 , 且没有被访问过, 且队列中没有这个值 , 重复 123步骤
    /***
     * 广度优先遍历
     *
     * @param arr
     * @param headValue
     */
    public void bfs(int[][] arr, int headValue) {
        Queue<Integer> queue = new LinkedList<>();
        queue.add(headValue);
        while (queue.size() > 0) {
            System.out.println(queue.peek());
            for (int i = 0; i < arr[headValue].length; i++) {
                if (arr[headValue][i] == 1&&!visited[i]&&!queue.contains(i)) {
                    queue.add(i);
                }
            }
            // 头节点出队
            Integer poll = queue.poll();
            visited[poll]=true;
            // 更新headValue;
            if (queue.size()>0){
                headValue=queue.peek();
            }
        }
    }

二叉树

假设我们有下面这个二叉树,

Binary Tree

下面我们使用不同的方式遍历它, 如果是深度优先的话, 情况依然是不确定的, 只要是符合一条路走到头, 没路可走再回退就ok , 比如 1 3 6 5 2 3 4

二叉树的深度优先搜索

下面使用java提供的栈这个数据结构辅助完成遍历的过程

思路:

  1. 将头节点压入栈
  2. 弹出栈顶的元素
  3. 打印弹出的栈顶的元素的值
  4. 处理栈顶元素的子节点
    1. 如果存在左子节点, 将做子节点压入栈
    2. 如果存在右子节点, 将右子节点压入栈
  5. 重复 1 2 3 4 过程...
   /**
     * 深度优先搜索
     * @param node
     */
    private static void dfs( Node node) {
        Stack<Node> stack = new Stack();
        stack.push(node);
        while (!stack.isEmpty()) {
            Node pop = stack.pop();
            System.out.println(pop.getValue());
            if (pop.getLeftNode()!=null){
                stack.push(pop.getLeftNode());
            }
            if (pop.getRightNode()!=null){
                stack.push(pop.getRightNode());
            }
        }
    }

Binary tree breadth-first search

Ideas: breadth-first traversal also by means of an auxiliary queue

  1. Vertex added to queue
  2. Print value of this node
  3. The left and right child nodes of the current process pushed onto the stack
    1. If there left node, the left node into queue
    2. If there is a right node, right node into the queue
  4. The head node from the team
  5. Repeat the process 1234
    /**
     * 广度优先搜索
     * @param node
     */
    private static void bfs( Node node) {
        Queue<Node> queue  = new LinkedList<>();
        queue.add(node);
        while (queue.size()>0){
            System.out.println(queue.peek().getValue());
            // 将左右节点入队
            if (queue.size()>0){
                Node nd = queue.poll();
                if (nd.getLeftNode()!=null){
                    queue.add(nd.getLeftNode());
                }
                if (nd.getRightNode()!=null){
                    queue.add(nd.getRightNode());
                }
            }
        }
    }

Guess you like

Origin www.cnblogs.com/ZhuChangwu/p/12056729.html