Estructura de datos: ¡le llevará a comprender todo el conocimiento de "imagen"! (Incluyendo DFS, BFS)

Prefacio

Este artículo explica principalmente la estructura del gráfico en la estructura de datos, incluida la primera búsqueda en profundidad (DFS), la primera búsqueda en amplitud (BFS), el algoritmo de árbol de expansión mínimo, etc. Espero que les guste.


Tabla de contenido

Diagrama esquemático


1. Introducción

  • Estructura de datos perteneciente a la estructura circular de la estructura lógica
  • Los detalles son los siguientes

Diagrama esquemático


2. Conceptos básicos

  • En la estructura de datos del gráfico, hay muchos conceptos básicos, como tipos de aristas, vértices de gráficos y relaciones entre aristas, etc.
  • Consulte la figura siguiente para obtener más detalles.

Diagrama esquemático


3. Escriba

Hay muchos tipos de gráficos, como sigue:

3.1 Gráfico dirigido y gráfico no dirigido

Diagrama esquemático

3.2 Gráfico conectado

  • Definición
    Cualquier vértice del gráfico es un gráfico conectado

  • Conceptos específicos relacionados
    Para gráficos dirigidos y gráficos no dirigidos, los conceptos específicos de gráficos conectados son diferentes, como sigue

Para gráficos no dirigidos:

Diagrama esquemático

Para gráficos dirigidos:

Diagrama esquemático

3.3 Otros tipos de diagramas

Diagrama esquemático


4. Estructura de almacenamiento

Hay 5 tipos de estructura de almacenamiento de la imagen, consulte la figura a continuación para obtener más detalles

Diagrama esquemático


5. Gráfico transversal

Estructura de datos: árbol binario detallado gráfico (transversal, tipo, operación)

5.1 Definición

A partir de un cierto vértice en el gráfico, recorra todos los demás vértices del gráfico y haga que cada vértice se visite solo una vez

5.2 Método de recorrido

Recorrido primero en profundidad ( DFS), recorrido primero en amplitud ( BFS)

5.3 Introducción específica

5.3.1 Primer recorrido en profundidad (DFS)
  • Introducción

Diagrama esquemático

  • Diagrama de algoritmo

Diagrama esquemático

  • Implementación específica: recursiva y no recursiva

La estructura de almacenamiento del gráfico aquí = matriz de adyacencia

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;
    }
}
  • Resultados de la prueba
深度优先遍历(递归)
A B C D E F G H I 
深度优先遍历(非递归)
A B C D E F G H I
  • Atención especial
    a la estructura de almacenamiento de la implementación de la tabla de adyacencia de FIG = , solo la matriz bidimensional puede almacenarse en la cadena lateral.

  • Estructura de almacenamiento de gráficos = comparación de rendimiento de la matriz de adyacencia / lista de adyacencia

Diagrama esquemático

5.3.2 Ancho de primer recorrido (BFS)
  • Introducción

Diagrama esquemático

  • Diagrama de algoritmo

Diagrama esquemático

  • proceso específico

Diagrama esquemático

Nota: Gproporción de Ilas razones para usar una matriz de acceso a la memoria = vértices, el subíndice de Gproporción de escala Imás pequeño más bajo (en ABCDEFGHIorden de almacenamiento)

  • Implementación

No recursivo: usar cola

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;
    }
        
}
  • Resultados de la
广度优先遍历(非递归):A B F C G I E D H

5.4 Comparación de métodos transversales

Diagrama esquemático


6. Árbol de expansión mínimo

Esta sección explica el árbol de expansión mínimo del dibujo

6.1 Definición

Construcción de un árbol de expansión de costo mínimo del gráfico de red conectada

  1. Gráfico neto: gráfico con pesos
  2. Costo mínimo: use (n-1) bordes para conectar un gráfico conectado con n vértices y minimizar la suma de pesos

6.2 Algoritmo para encontrar el árbol de expansión mínimo

  • Incluye principalmente: Prim( Kruskal) algoritmo Primm y ( ) algoritmo Kruskal
  • Los detalles son los siguientes

6.2.1 (Prim) Algoritmo de Prim

  • Descripción general del algoritmo

Diagrama esquemático

  • Diagrama esquemático del flujo del principio del algoritmo

Diagrama esquemático

  • por ejemplo

Diagrama esquemático

6.2.2 (Kruskal) Algoritmo de Kruskal

  • Descripción general del algoritmo

Diagrama esquemático

6.3 Comparación de algoritmos

Diagrama esquemático


7. El camino más corto

7.1 Definición

  • Para gráficos no netos (sin peso), la ruta más corta = la ruta con el menor número de aristas entre dos vértices
  • Para el gráfico de red (pesos): el camino más corto = el peso del borde pasado entre dos vértices y el camino mínimo

1er vértice = punto de origen, 2do vértice = punto final

7.2 Problemas a resolver

La ruta más corta desde el punto de origen -> los vértices restantes

7.3 Encontrar el algoritmo de ruta más corta

  • Incluyen principalmente: algoritmo de Dijkstra, algoritmo de (Dijkstra)Freud(Floyd)

  • Los detalles son los siguientes

Diagrama esquemático


8. Resumen


Bangding / ¡Me gusta el comentario! ¡Porque tu aliento es mi mayor motivación para escribir!

Supongo que te gusta

Origin blog.csdn.net/carson_ho/article/details/108571561
Recomendado
Clasificación