Data structure: take you to understand all the knowledge of "picture"! (Including DFS, BFS)

Preface

This article mainly explains the graph structure in the data structure, including depth first search (DFS), breadth first search (BFS), minimum spanning tree algorithm, etc. I hope you will like it.


table of Contents

Schematic diagram


1 Introduction

  • Data structure belonging to the circular structure of the logical structure
  • The details are as follows

Schematic diagram


2. Basic concepts

  • In the graph data structure, there are many basic concepts, such as edge types, graph vertices & relationships between edges, etc.
  • See the figure below for details

Schematic diagram


3. Type

There are many types of graphs, as follows:

3.1 Directed Graph & Undirected Graph

Schematic diagram

3.2 Connected graph

  • Definition
    Any vertex in the graph is a connected graph

  • Specific related concepts
    For directed graphs & undirected graphs, the specific concepts of connected graphs are different, as follows

For undirected graphs:

Schematic diagram

For directed graphs:

Schematic diagram

3.3 Other types of diagrams

Schematic diagram


4. Storage structure

There are 5 types of storage structure of the picture, please see the figure below for details

Schematic diagram


5. Graph traversal

Data structure: Graphical detailed binary tree (traversal, type, operation)

5.1 Definition

Starting from a certain vertex in the graph, traverse all the other vertices in the graph & make each vertex be visited only once

5.2 Traversal method

Depth-first traversal ( DFS), breadth-first traversal ( BFS)

5.3 Specific introduction

5.3.1 Depth First Traversal (DFS)
  • Introduction

Schematic diagram

  • Algorithm diagram

Schematic diagram

  • Specific implementation: recursive & non-recursive

The storage structure of the graph here = adjacency matrix

import java.util.Stack;

public class MyGraph {

    /**
     * 准备工作1:设置变量
     */
    private int vexnum;  // 存放图中顶点数量
    private char[] vertices;  // 存放结点数据
    private int [][] arcs;  // 存放图的所有边
    private boolean[] visited;// 记录节点是否已被遍历

    /**
     * 准备工作2:初始化图的顶点数量、数据 & 边
     */
    public MyGraph(int n){
        vexnum = n;
        vertices = new char[n];
        visited = new boolean[n];
        arcs = new int[n][n];
    }

    /**
     * 图的深度优先遍历算法实现:递归
     * 类似 前序遍历
     */
    public void DFSTraverse(){
        // 1. 初始化所有顶点的访问标记
        // 即,都是未访问状态
        for (int i = 0; i < vexnum; i++) {
            visited[i] = false;
        }

        // 2. 深度优先遍历顶点(从未被访问的顶点开始)
        for(int i=0;i < vexnum;i++){

            if(visited[i]==false){

                // 若是连通图,只会执行一次
                traverse(i); // ->>看关注1
            }
        }
    }

    /**
     * 关注1:邻接矩阵的深度优先搜索递归算法
     * 即,从第i个顶点开始深度优先遍历
     */
    private void traverse(int i){

        // 1. 标记第i个顶点已遍历
        visited[i] = true;

        // 2. (输出)访问当前遍历的顶点
        visit(i);

        // 3. 遍历邻接矩阵中第i个顶点的所有邻接顶点
        for(int j=0;j<vexnum;j++){

            // a. 若当前顶点的邻接顶点存在 & 未被访问,则递归 深度优先搜索 算法

            if(arcs[i][j]==1 && visited[j]==false){
                // b. 将当前顶点的邻接顶点作为当前顶点,递归 深度优先搜索 算法
                traverse(j);
            }
        }
    }
    
    /**
     * 辅助算法1:访问顶点值
     */
    public void visit(int i){
        System.out.print(vertices[i] + " ");
    }

    
    
    /**
     * 图的深度优先遍历算法实现:非递归
     * 原理:采用 栈实现
     */
    public void DFSTraverse2(){
        // 1. 初始化顶点访问标记
        // 全部标记为:未访问
        for (int i = 0; i < vexnum; i++) {
            visited[i] = false;
        }

        // 2. 创建栈
        Stack<Integer> s = new Stack<Integer>();


        for(int i=0 ; i<vexnum; i++){

            // 3. 若该顶点未被访问
            if(!visited[i]){
                // 4. 入栈该顶点

                s.add(i);

                do{
                    // 出栈
                    int curr = s.pop();

                    // 如果该节点还没有被遍历,则遍历该节点并将子节点入栈
                    if(visited[curr]==false){
                        // 遍历并打印
                        visit(curr);
                        visited[curr] = true;

                        // 没遍历的子节点入栈
                        for(int j=vexnum-1; j>=0 ; j-- ){
                            if(arcs[curr][j]==1 && visited[j]==false){
                                s.add(j);
                            }
                        }
                    }
                }while(!s.isEmpty());
            }
        }
    }

    
    /**
     * 测试(递归 & 非递归)
     */
    public static void main(String[] args) {

        // 1. 初始化图的结构(顶点数量 = 9)
        MyGraph g = new MyGraph(9);

        // 2. 设置顶点数据
        char[] vertices = {'A','B','C','D','E','F','G','H','I'};
        g.setVertices(vertices);

        // 3. 设置边
        g.addEdge(0, 1);
        g.addEdge(0, 5);
        g.addEdge(1, 0);
        g.addEdge(1, 2);
        g.addEdge(1, 6);
        g.addEdge(1, 8);
        g.addEdge(2, 1);
        g.addEdge(2, 3);
        g.addEdge(2, 8);
        g.addEdge(3, 2);
        g.addEdge(3, 4);
        g.addEdge(3, 6);
        g.addEdge(3, 7);
        g.addEdge(3, 8);
        g.addEdge(4, 3);
        g.addEdge(4, 5);
        g.addEdge(4, 7);
        g.addEdge(5, 0);
        g.addEdge(5, 4);
        g.addEdge(5, 6);
        g.addEdge(6, 1);
        g.addEdge(6, 3);
        g.addEdge(6, 5);
        g.addEdge(6, 7);
        g.addEdge(7, 3);
        g.addEdge(7, 4);
        g.addEdge(7, 6);
        g.addEdge(8, 1);
        g.addEdge(8, 2);
        g.addEdge(8, 3);

        // 4. 执行 图的深度优先遍历:(递归 & 非递归)
        System.out.println("深度优先遍历(递归)");
        g.DFSTraverse();
        System.out.println("深度优先遍历(非递归)");
        g.DFSTraverse2();

    }

    /**
     * 辅助算法1:添加边(无向图)
     */
    public void addEdge(int i, int j) {
        // 边的头尾不能为同一节点
        if (i == j) return;

        // 将邻接矩阵的第i行第j列的元素值置为1;
        arcs[i][j] = 1;
        // 将邻接矩阵的第j行第i列的元素值置为1;
        arcs[j][i] = 1;
        // 设置为1代表2顶点之间存在 边 (设置相等原因 = 邻接矩阵 是对称的)
    }

    /**
     * 辅助算法2:设置顶点数据
     */
    public void setVertices(char[] vertices) {
        this.vertices = vertices;
    }
}
  • Test Results
深度优先遍历(递归)
A B C D E F G H I 
深度优先遍历(非递归)
A B C D E F G H I
  • Special attention
    to the storage structure of FIG = adjacency table implementation, only the two-dimensional array can be stored side chain into.

  • Graph storage structure = performance comparison of adjacency matrix / adjacency list

Schematic diagram

5.3.2 Breadth First Traversal (BFS)
  • Introduction

Schematic diagram

  • Algorithm diagram

Schematic diagram

  • specific process

Schematic diagram

Note: Gratio of Ithe reasons to use an array of memory access = vertices, the Gscale ratio Isubscript smaller lower (in ABCDEFGHIorder of storage)

  • Implementation

Non-recursive: use queue

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class MyGraph {

    /**
     * 准备工作1:设置变量
     */
    private int vexnum;  // 存放图中顶点数量
    private char[] vertices;  // 存放结点数据
    private int [][] arcs;  // 存放图的所有边
    private boolean[] visited;// 记录节点是否已被遍历

    /**
     * 准备工作2:初始化图的顶点数量、数据 & 边
     */
    public MyGraph(int n){
        vexnum = n;
        vertices = new char[n];
        visited = new boolean[n];
        arcs = new int[n][n];
    }
    
    /**
     * 广度优先搜索 算法实现
     * 原理:非递归(采用队列)
     */
    public void BFS(){

        // 1. 初始化所有顶点的访问标记
        // 即,设置为未访问状态
        for (int i = 0; i < vexnum; i++) {
            visited[i] = false;
        }

        // 2. 创建队列
        Queue<Integer> q=new LinkedList<Integer>();

        // 3. 对所有顶点做遍历循环(从第1个顶点开始)
        // 若遍历完毕,则结束整个层序遍历
        for(int i=0;i < vexnum;i++){

            // 4. 若当前顶点未被访问,就进行处理
            // 若当前顶点已被访问,则回到3进行判断
            if( visited[i]==false ) {

                // 5. (输出)访问当前顶点
                visit(i);

                // 6. 标记当前顶点已被访问
                visited[i] = true;

                // 7. 入队当前顶点
                q.add(i);

                // 8.判断当前队列是否为空
                // 若为空则跳出循环,回到3进行判断
                while(!q.isEmpty()) {

                    // 9. 出队队首元素 & 将出队的元素 赋值为 当前顶点
                    i =  q.poll();

                    // 10. 遍历当前顶点的所有邻接点
                    // 若遍历完毕,则回到8判断
                    for(int j=0; j< vexnum ; j++){

                        // 11. 若当前顶点的邻接顶点存在 & 未被访问,则执行处理
                        // 否则回到10判断
                        if(arcs[i][j]==1 && visited[j]==false){

                            // 12. (输出)访问当前顶点的邻接顶点
                            visit(j);

                            // 13. 标记当前顶点的邻接顶点已被访问
                            visited[j] = true;

                            // 14. 入队当前顶点的邻接顶点
                            q.add(j);

                        }
                    }

                }

            }
        }
    }

  /**
    * 辅助算法1:访问该顶点
    */
    public void visit(int i){
        System.out.print(vertices[i] + " ");
    }

  /** 
    * 测试算法
    */
    public static void main(String[] args) {
        // 1. 初始化图的结构(顶点数量 = 9
        MyGraph g = new MyGraph(9);

        // 2. 设置顶点数据
        char[] vertices = {'A','B','C','D','E','F','G','H','I'};
        g.setVertices(vertices);

        // 3. 设置边
        g.addEdge(0, 1);
        g.addEdge(0, 5);
        g.addEdge(1, 0);
        g.addEdge(1, 2);
        g.addEdge(1, 6);
        g.addEdge(1, 8);
        g.addEdge(2, 1);
        g.addEdge(2, 3);
        g.addEdge(2, 8);
        g.addEdge(3, 2);
        g.addEdge(3, 4);
        g.addEdge(3, 6);
        g.addEdge(3, 7);
        g.addEdge(3, 8);
        g.addEdge(4, 3);
        g.addEdge(4, 5);
        g.addEdge(4, 7);
        g.addEdge(5, 0);
        g.addEdge(5, 4);
        g.addEdge(5, 6);
        g.addEdge(6, 1);
        g.addEdge(6, 3);
        g.addEdge(6, 5);
        g.addEdge(6, 7);
        g.addEdge(7, 3);
        g.addEdge(7, 4);
        g.addEdge(7, 6);
        g.addEdge(8, 1);
        g.addEdge(8, 2);
        g.addEdge(8, 3);

        // 4. 执行 图的广度优先遍历(非递归)
        System.out.print("广度优先遍历(非递归):");
        g.BFS();
        }

  /**
    * 辅助算法1:添加边(无向图)
    */

    public void addEdge(int i, int j) {
        // 边的头尾不能为同一节点
        if (i == j) return;

        // 将邻接矩阵的第i行第j列的元素值置为1;
        arcs[i][j] = 1;
        // 将邻接矩阵的第j行第i列的元素值置为1;
        arcs[j][i] = 1;
        // 设置为1代表2顶点之间存在 边 (设置相等原因 = 邻接矩阵 是对称的)
    }

    /**
     * 辅助算法2:设置顶点数据
     */
    public void setVertices(char[] vertices) {
        this.vertices = vertices;
    }
        
}
  • Results of the
广度优先遍历(非递归):A B F C G I E D H

5.4 Comparison of traversal methods

Schematic diagram


6. Minimum spanning tree

This section explains the drawing minimum spanning tree

6.1 Definition

Constructing minimum cost spanning tree of connected network graph

  1. Net graph: graph with weights
  2. Minimal cost: Use (n-1) edges to connect a connected graph with n vertices & minimize the sum of weights

6.2 Algorithm for finding the minimum spanning tree

  • Mainly include: Prim( Kruskal) Primm algorithm & ( ) Kruskal algorithm
  • The details are as follows

6.2.1 (Prim) Prim's algorithm

  • Algorithm overview

Schematic diagram

  • Schematic diagram of algorithm principle flow

Schematic diagram

  • for example

Schematic diagram

6.2.2 (Kruskal) Kruskal Algorithm

  • Algorithm overview

Schematic diagram

6.3 Algorithm comparison

Schematic diagram


7. The shortest path

7.1 Definition

  • For non-net graphs (without weight), the shortest path = the path with the least number of edges between two vertices
  • For the network graph (weights): the shortest path = the weight of the edge passed between two vertices and the least path

1st vertex = source point, 2nd vertex = end point

7.2 Problems to be solved

The shortest path from the source point -> the remaining vertices

7.3 Find the shortest path algorithm

  • Mainly include: Dijkstra's algorithm (Dijkstra), Freud's algorithm(Floyd)

  • The details are as follows

Schematic diagram


8. Summary

  • This article mainly explains the graphs in the data structure
  • Now I will continue to data structures , are interested can continue to focus on Carson_Ho Android Development Notes

Bangding / Like the comment! Because your encouragement is my biggest motivation for writing!

Guess you like

Origin blog.csdn.net/carson_ho/article/details/108571561