• 图的使用场景和常用算法


    一.什么是图?有哪些特性及其使用场景?

       由来: 当我们需要表示多对多的关系的时候,就需要使用到图这种数据结构

       定义: 图是一种数据结构,其中顶点可以是具有零个或多个相邻元素.两个顶点之间的连线称为边,节点被称为顶点

                

        常用概念:  无向图表示顶点之间的连接没有方向,既可以A->B,也可以B->A,有向图表示顶点之间的连接有方向,A->B,B->A,表示不同的路径

            

       图的创建: 邻接矩阵(使用二维数组)和邻接表(使用链表)

    public class Graph {
    
        private List<String> vertexList;  // 存储顶点的集合
        private int[][] edges;            // 存储图对应的邻接矩阵
        private int numberOfEdges;        // 表示边的数量
        private boolean[] isVisited;      // 是否被访问过
    
        public static void main(String[] args) {
            Graph graph = new Graph(5);
            String[] vertexes = {"A","B","C","D","E"};
            // 添加节点
            for (String vertex : vertexes) {
                graph.insertVertex(vertex);
            }
            // 添加边 A-B A-C B-C B-D B-E 用于创建邻接矩阵
            graph.insertWeight(0,1,1);
            graph.insertWeight(0,2,1);
            graph.insertWeight(1,2,1);
            graph.insertWeight(1,3,1);
            graph.insertWeight(1,4,1);
    
            graph.showGraph();
        }
    
        /**
         * 构造器 ,初始化顶点,邻接矩阵,边的数目,是否访问过
         * @param n
         */
        public Graph(int n) {
            vertexList = new ArrayList<String> (n);
            edges = new int[n][n];
            isVisited = new boolean[n];
            numberOfEdges = 0;
        }
    }

     /**
         * 插入顶点
         * @param vertex
         */
        public void insertVertex(String vertex){
            vertexList.add(vertex);
        }
    
        /**
         * 添加边 无向图
         * @param v1        表示第一个顶点对应的下标
         * @param v2        表示第二个顶点对应的下标
         * @param weight    表示权值
         */
        public void insertWeight(int v1,int v2,int weight){
            edges[v1][v2] = weight;
            edges[v2][v1] = weight;
            numberOfEdges++;
        }

     执行结果:

    二.图的遍历

        深度优先遍历(dfs)

     基本思想:

         1.从初始访问的节点出发,初始访问的节点可能有多个邻接节点,深度优先遍历的策略是首先访问第一个邻接节点,然后在把这个被访问过的邻接节点

            作为初始节点,在访问它的邻接节点.即每次访问完当前节点后首先访问当前节点的第一个邻接节点

          2.这样的访问策略是优先纵向的挖掘深入,而不是对所有的节点进行横向的访问

          3.这是一个递归调用的过程

     步骤:  

         1.访问初始节点v,并将v标记为已访问

         2.查找节点v的第一个邻接节点w

                      3.若w存在,继续执行4,如果不存在,回到第1步,继续从v的下一个节点继续  

            4.若w未被访问,对w进行深度优先访问

            5.查找节点v的w邻接节点的下一个邻接节点,转到步骤3    

                   

    /**
         * 返回节点i对应的数据
         * @param i
         * @return
         */
        public String getValueByIndex(int i){
            return vertexList.get(i);
        }
    
    
    /**
         * 找到第一个相邻节点的下标
         * @param index
         * @return
         */
        public int getFirstNeighbor(int index){
            for (int j = 0; j < vertexList.size(); j++) {
                if (edges[index][j] != 0){
                    return j;
                }
            }
            return -1;
        }
    
    /**
         * 根据前一个相邻节点的下标获取下一个相邻节点的下标
         * @param v1
         * @param v2
         * @return
         */
        public int getNextNeighbor(int v1,int v2){
            for (int j = v2+1; j < vertexList.size(); j++) {
                if (edges[v1][j] != 0) {
                    return j;
                }
            }
            return -1;
        }
    
    /**
         * 深度优先遍历
         * @param isVisited
         * @param i
         */
        private void  dfs(boolean[] isVisited,int i){
            // 访问当前的节点
            System.out.print(getValueByIndex(i) +"->");
            // 将被访问的节点设置成已访问
            isVisited[i] = true;
            // 获取当前节点的相邻的节点
            int w = getFirstNeighbor(i);
            while (w != -1){ // 只要当前节点的邻接点不为空
                if (!isVisited[w]){ // 如果没有访问过
                    dfs(isVisited, w); //继续递归
                }
                // 继续从它的下一个邻接点开始执行
                w = getNextNeighbor(i,w);
            }
        }
    
     public void dfs(){
            isVisited = new boolean[vertexList.size()];
            for (int i = 0; i < vertexList.size(); i++) {
                if (!isVisited[i]) {
                    dfs(isVisited, i);
                }
            }
        }

    执行结果:

      

     广度优先遍历(bfs)

      基本思想:

          类似于分层搜索的过程,需要使用一个队列来保存访问过的节点顺序,以便按照这个顺序来访问这些节点的邻接节点

      步骤:

          1.访问初始节点v,并将v标记为已访问

          2.节点v入队列

          3.当队列非空时,继续执行,否则算法结束

          4.出队列,取出队列头u

          5.查找u的第一个邻接节点w

          6.若节点u的的邻接节点w不存在,转回步骤3,否则执行步骤7

          7.若节点w尚未被访问,则将w标记为已访问

          8.节点w入队列

          9.查找节点u的继w的邻接节点后的下一个邻接节点,重复步骤6直到队列为空

    /**
         * 广度优先遍历
         * @param isVisited
         * @param i
         */
        private void bfs(boolean[] isVisited, int i){
            int u; // 表示队列头结点对应的下标
            int w; // 邻接节点w
            // 用于记录节点访问的顺序
            Queue<Integer> queue = new LinkedList<>();
            // 访问节点,输出节点的值
            System.out.print(getValueByIndex(i) + "->");
            // 将已访问的节点标记为已访问
            isVisited[i] = true;
            // 将已访问的节点加入到队列
            queue.add(i);
            while (!queue.isEmpty()){
                // 取出队列头节点的下标
                u = queue.remove();
                // 得到其邻接节点的下标
                w = getFirstNeighbor(u);
                while (w != -1){ // 如果邻接节点存在
                    if(!isVisited[w]){ // 是否已经访问过该节点
                        System.out.print(getValueByIndex(w) + "->"); // 访问该节点
                        isVisited[w] = true; // 将该节点的状态设置为已访问
                        queue.add(w); // 加入到队列中
                    }
                    w = getNextNeighbor(u,w); //以u为前驱节点,找到其下一个节点
                }
            }
        }
    
    public void bfs(){
            isVisited = new boolean[vertexList.size()];
            for (int i = 0; i < vertexList.size(); i++) {
                if (!isVisited[i]) {
                    bfs(isVisited,i);
                }
            }
        }

     执行结果:

     三.求解图的最小生成树

      什么是最小生成树?

        1.给定一个带权的无向连通图,如何选取一颗生成树,使得树上所有边上权的总和为最小,就叫最小生成树

        2.有N个顶点,一定会有N-1条边,并且包含全部的顶点

                         

     如何求得最小生成树

       1.普里姆算法

        步骤:

          1.设G=(V,E)是联通网,T=(U,D)是最小生成树,V,U是顶点集合,E,D是边的集合

          2.若从顶点u开始构建最小生成树,则从集合V中取出顶点u放入到集合U中,并标记顶点v为已访问

          3.若集合U中的顶点ui和集合U-V的顶点vj之间存在边,则寻找这些边权值的最小边,但不能构成回路,将顶点vj加入集合U中,标记顶点v已访问

          4.重复步骤2,直到集合V和U相等,并且所有的顶点都标记为已访问,此时D中就有n-1条边

                        

       创建图对象并初始化

    class MGraph{
        int vertexes; // 图的节点个数
        char[] data;  // 存放顶点坐标  
        int[][] weight;// 存放边,即邻接矩阵
    
        public MGraph(int vertexes) {
            this.vertexes = vertexes;
            data = new char[vertexes];
            weight = new int[vertexes][vertexes];
        }
    
    }
    class MinTree {
        /**
         * 创建图对象
         * @param graph
         * @param vertexes
         * @param data
         * @param weight
         */
        public void createGraph(MGraph graph,int vertexes,char[] data,int[][] weight){
            for (int i = 0; i < vertexes; i++) {
                graph.data[i] = data[i];
                for (int j = 0; j < vertexes; j++){
                    graph.weight[i][j] = weight[i][j];
                }
            }
        }
    
        /**
         * 显示图的邻接矩阵
         * @param graph
         */
        public  void show(MGraph graph){
            for(int[] link:graph.weight){
                System.out.println(Arrays.toString(link));
            }
        }
    }
     public static void main(String[] args) {
            char[] data = {'A','B','C','D','E','F','G'};
            int vertexes = data.length;
            // 使用10000表示两条线之间不连通
            int[][] weight = {
                    {10000,5,7,10000,10000,10000,2},
                    {5,10000,10000,9,10000,10000,3},
                    {7,10000,10000,10000,8,10000,10000},
                    {10000,9,10000,10000,10000,4,10000},
                    {10000,10000,8,10000,10000,5,4},
                    {10000,10000,10000,4,5,10000,6},
                    {2,3,10000,10000,4,6,10000},};
    
            MinTree minTree = new MinTree();
            MGraph graph = new MGraph(vertexes);
            minTree.createGraph(graph,vertexes,data,weight);
            minTree.show(graph);
        }
    }

    执行结果:

          

       实现普利姆算法,假设从G点开始走

    /**
         * 普利姆算法
         * @param graph 图对象
         * @param v     从哪个顶点开始
         */
        public void prim(MGraph graph,int v){
            // 存放访问过的节点
            int[] visited = new int[graph.vertexes];
            //初始化visited的值
            for (int i = 0; i < graph.vertexes;i++){
                visited[i] = 0;
            }
            // 把当前的节点标记为已访问
            visited[v] = 1;
            // h1和h2 记录两个顶点的下标
            int h1 = -1;
            int h2 = -1;
            // 把minWeight设置为一个最大值,表示两个点不能连通,后续会替换
            int minWeight = 10000;
    
            for (int k = 1; k < graph.vertexes;k++){ // 因为有vertexes个顶点,所以结束后,会生成vertexes-1条边,边的数量
                for (int i = 0; i < graph.vertexes;i++){ //  i表示已经访问过的节点
                    for (int j = 0; j < graph.vertexes;j++){// j表示未访问过的节点
                        if (visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight){ // 寻找已访问的节点和未访问过的节点间的权值最小的边
                            minWeight = graph.weight[i][j]; // 将minWeight的值更新为图的权重值
                            h1 = i;                // h1更新为已访问
                            h2 = j;               //  h2更新为已访问 
                        }
                    }
                }
                System.out.println("<" + graph.data[h1] + ", "+graph.data[h2] + "> 权值:"+ minWeight);
                // 把当前的节点设置为已访问
                visited[h2] = 1;
                // 重置minWeight的值
                minWeight = 10000;
            }
        }

    执行结果:

        

     2.克鲁斯卡尔算法

         步骤:

        1.按照权值从到到小进行排序

        2.保证这些边不构成回路

      1.创建图

    public class KruskalDemo {
    
        private int edgeNums;  // 边的数量
        private char[] vertexes; // 顶点的集合
        private int[][] matrix;  // 邻接矩阵
        private static final int INF = Integer.MAX_VALUE;// 表示两点之间不能联通
    
    
        public static void main(String[] args) {
            char[] vertexes = {'A','B','C','D','E','F','G'};
            int matrix[][] = {
                    /*A*//*B*//*C*//*D*//*E*//*F*//*G*/
                    /*A*/ {   0,  12, INF, INF, INF,  16,  14},
                    /*B*/ {  12,   0,  10, INF, INF,   7, INF},
                    /*C*/ { INF,  10,   0,   3,   5,   6, INF},
                    /*D*/ { INF, INF,   3,   0,   4, INF, INF},
                    /*E*/ { INF, INF,   5,   4,   0,   2,   8},
                    /*F*/ {  16,   7,   6, INF,   2,   0,   9},
                    /*G*/ {  14, INF, INF, INF,   8,   9,   0}};
    
    
            KruskalDemo kruskal = new KruskalDemo(vertexes,matrix);
            kruskal.show();
        }
    
        /*初始化顶点和邻接矩阵*/
        public KruskalDemo(char[] vertexes,int[][] matrix){
            // 构造方法
            int vlen = vertexes.length;
    
            //使用复制拷贝的方法初始化顶点
            this.vertexes = new char[vlen];
            for (int i = 0; i < vertexes.length; i++){
                this.vertexes[i] = vertexes[i];
            }
    
            // 使用复制拷贝的方法,初始化边(权值)
            this.matrix = new int[vlen][vlen];
            for (int i = 0; i < vertexes.length; i++){
                for (int j = 0; j < vertexes.length; j++){
                    this.matrix[i][j] = matrix[i][j];
                }
            }
    
            // 初始化有效边的数量
            for (int i = 0; i < vertexes.length; i++){
                // 自己和自己不算有效边
                for (int j = i+1; j < vertexes.length; j++){
                    if (this.matrix[i][j] != INF){
                        edgeNums++;
                    }
                }
            }
    
        }
    
        public void show(){
            for (int i = 0; i < vertexes.length;i++){
                for (int j = 0; j < vertexes.length; j++){
                    System.out.printf("%d	",matrix[i][j]);
                }
                System.out.println();
            }
        }
    }

    执行结果:

          

      创建边,根据权值进行升序排列

    class Edata implements Comparable<Edata>{
        public char start; // 边的起始点
        public char end; // 边的终点
        public int weight; // 边的权值
    
        public Edata(char start, char end, int weight) {
            this.start = start;
            this.end = end;
            this.weight = weight;
        }
    
        @Override
        public String toString() {
            return "Edata [<" + start +","+end+">= "+weight+"]";
        }
    
        @Override
        public int compareTo(Edata o) {
            // 升序排列
            return this.weight - o.weight;
        }
    }

      判断两条边是否是同一个终点,如果不是就加入到树中,直到树扩大成一个森林

    /**
         * 返回一个顶点对应的下标值,找不到返回-1
         * @param ch
         * @return
         */
        private int getPosition(char ch){
            for (int i = 0; i < vertexes.length;i++){
                if (vertexes[i] == ch ){
                    return i;
                }
            }
            return - 1;
        }
    
     /**
         * 获取图中的边,放入到Edata数组中,
         * @return
         */
        private Edata[] getEdges(){
            int index = 0;
            Edata[] edges = new Edata[edgeNums];
            for (int i = 0; i < vertexes.length;i++){
                for (int j = i+1; j < vertexes.length; j++) {
                    if (matrix[i][j] != INF){
                        edges[index++] = new Edata(vertexes[i],vertexes[j],matrix[i][j]);
                    }
                }
            }
            return edges;
        }
    
    /**
         * 获取下标为i顶点对应的终点,用于判断两个顶点的终点是否相同
         * @param ends 记录了各个顶点对应的终点是哪个,在遍历过程中,逐步形成
         * @param i    传入的顶点对应的下标
         * @return     返回这个顶点的终点对应的下标
         */
        private int getEnd(int[] ends,int i){
            while (ends[i] != 0){
                i = ends[i];
            }
            return i;
        }

       完成算法

    public void kruskal(){
            int index = 0; // 表示最后结果的数组索引
            int[] ends = new int[edgeNums]; // 用于保存已有最小生成树中每个顶点的终点
            Edata[] rets = new Edata[edgeNums]; // 创建结果数组,保留最后的最小生成树
    
            Edata[] edges = getEdges(); // 获取所有边的集合
            Collections.sort(Arrays.asList(edges)); // 排序
           // System.out.println("图的边的集合=" + Arrays.toString(edges) + " 共"+ edges.length);
            // 将边添加到最小生成树中,同时判断是否生成回路
            for (int i = 0; i < edgeNums; i++){
                // 获取第i条边的第一个顶点
                int p1 = getPosition(edges[i].start);
                // 获取第i条边的第二个顶点
                int p2 = getPosition(edges[i].end);
    
                // 获取p1这个顶点在已有最小生成树中的终点
                int m = getEnd(ends,p1);
                // 获取p2这个顶点在已有最小生成树中的终点
                int n = getEnd(ends,p2);
                // 是否构成回路
                if (m != n){ // 如果没有构成回路
                    ends[m] = n; // 设置m在已有最小生成树中的终点
                    rets[index++] = edges[i]; // 将这条边加入到结果数组
                }
            }
    
            System.out.println("最小生成树为:");
            for (int i = 0; i < index; i++){
                System.out.println(rets[i]);
            }
        }

    执行结果:

               

     四.求出图的最短路径

      1.迪杰斯特拉算法(从单一顶点出发到其他的各个顶点的最小路径)

            

         步骤:

           1.设出发顶点为v,顶点集合V{v1,v2,...vi},v到V中各顶点集合的距离集合Dis,Dis{d1,d2,...di},Dis记录了v到图中各个顶点的距离(到自身可以看做是0,v到vi对应的距离是di)

              2.从Dis中选择值最小的di并移出Dis集合,同时移除V集合对应的顶点vi,此时的v到vi即为最短路径

            3.更新Dis集合,比较v到V集合中顶点的距离值,与v通过vi到V集合中顶点的距离值,保留较小的那个(同时也应该更新顶点的前驱节点为vi,表示通过vi达到的)

            4.重复步骤2和3,直到最短路径顶点为目标顶点即可结束

      初始化图

    public static void main(String[] args) {
            char[] vertexes = {'A','B','C','D','E','F','G'};
            int[][] matrix = new int[vertexes.length][vertexes.length];
            final int N = 65535;// 表示不可以连接
            matrix[0]=new int[]{N,5,7,N,N,N,2};
            matrix[1]=new int[]{5,N,N,9,N,N,3};
            matrix[2]=new int[]{7,N,N,N,8,N,N};
            matrix[3]=new int[]{N,9,N,N,N,4,N};
            matrix[4]=new int[]{N,N,8,N,N,5,4};
            matrix[5]=new int[]{N,N,N,4,5,N,6};
            matrix[6]=new int[]{2,3,N,N,4,6,N};
    
            Graph g = new Graph(vertexes,matrix);
            g.showGraph();
          
        }
    class Graph {
        public char[] vertexes;
        public int[][] matrix;
        public VisitedVertex vv;
    
        public Graph(char[] vertexes, int[][] matrix) {
            this.vertexes = vertexes;
            this.matrix = matrix;
        }
    
        public void showGraph(){
            for (int[] links:matrix){
                System.out.println(Arrays.toString(links));
            }
        }
    }

     执行结果:

              

       初始化前驱节点,已访问节点和距离

    class VisitedVertex {
    
        /*记录各个顶点是否访问过,1表示已访问,0表示未访问*/
        public int[] already_arr;
        /*记录每一个下标对应值的前一个下标,动态更新*/
        public int[] pre_visited;
        /*记录出发顶点到各个顶点的距离*/
        public int[] dis;
    
        /**
         *
         * @param length 初始化顶点的个数
         * @param index  从哪个顶点开始
         */
        public VisitedVertex(int length,int index) {
            already_arr = new int[length];
            pre_visited = new int[length];
            dis = new int[length];
            /*初始化dis数组*/
            Arrays.fill(dis,65535);
            /*设置除法顶点被访问过*/
            this.already_arr[index] = 1;
            /*设置出发顶点的访问距离为0*/
            this.dis[index] = 0;
        }
    
        /**
         * 判断某各顶点是否被访问过
         * @param index
         * @return
         */
        public boolean in(int index){
            return already_arr[index] == 1;
        }
    
        /**
         *  更新出发顶点到index节点的距离
         * @param index
         * @param len
         */
        public void updateDis(int index,int len){
            dis[index] = len;
        }
    
        /**
         * 更新pre这个顶点的前驱节点为index顶点
         * @param pre
         * @param index
         */
        public void updatePre(int pre,int index){
            pre_visited[pre] = index;
        }
    
        /**
         * 返回出发顶点到index的距离
         * @param index
         * @return
         */
        public int getDis(int index){
            return dis[index];
        }
    
        /**
         * 继续选择并返回新的访问节点
         * @return
         */
        public int updateArr(){
            int min = 65535;
            int index = 0;
            for (int i = 0; i < already_arr.length;i++){
                if (already_arr[i] == 0 && dis[i] < min){ //使用广度优先的策略,如果初始节点的下一个没有被访问,并且可以连通,就选择下一个节点为出发节点
                    min = dis[i];
                    index = i;
                }
            }
            /*更新index顶点被访问过*/
            already_arr[index] = 1;
            return index;
        }
    
        
    }

      更新周围顶点和前驱节点的距离,完成算法

    public void djs(int index){
            vv = new VisitedVertex(vertexes.length,index);
            /*更新index顶点到周围顶点的距离和前驱节点*/
            update(index);
           
            for (int j = 1; j < vertexes.length; j++) {
                /*选择并返回新的访问节点*/
                index = vv.updateArr();
                /*更新index顶点到周围顶点的距离和前驱节点*/
                update(index);
            }
        }
    
        /**
         * 更新index下标顶点周围顶点的距离和周围顶点的前驱节点
         * @param index
         */
        public void update(int index){
            int len = 0;
            /*遍历邻接矩阵的matrix[index]所对应的行*/
            for (int i = 0; i < matrix[index].length; i++) {
                /*出发顶点到index顶点的距离 + 从index到i顶点的距离和*/
                len = vv.getDis(index) + matrix[index][i];
                /*如果i顶点没有被访问过,并且len小于出发顶点到j顶点的距离,就需要更新*/
                if (!vv.in(i) && len < vv.getDis(i)){
                    /*更新i点的前驱节点为index节点*/
                    vv.updatePre(i,index);
                    /*更新出发顶点到i的距离*/
                    vv.updateDis(i,len);
                }
            }
        }

     执行结果:

              

       2.弗洛伊德算法(求出所有顶点到其他各个顶点的最短距离)

        步骤:

          1.设顶点vi到vk的最短路径已知是Lik,顶点vk到vj的最短路径已知是Lkj,顶点vi到vj的路径为Lij,那么vi到vj的最短路径是min((Lik+Lkj),Lij),vk的取值为图中所有的顶点

           则可以获得vi到vj的最短路径

          2.vi到vk的最短路径Lik,vj到vk的最短路径Lkj,可以用同样的方式获得(递归)

      初始化图

    public static void main(String[] args) {
            char[] vertexes = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
            //创建邻接矩阵
            int[][] matrix = new int[vertexes.length][vertexes.length];
            final int N = 65535;
            matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
            matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
            matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
            matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
            matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
            matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
            matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };
    
            FGraph fGraph = new FGraph(vertexes,matrix,vertexes.length);
          
            fGraph.show();
        }
    
    class FGraph{
    
        public char[] vertexes;  // 存放各个顶点的数组
        public int[][] dis;     // 存放各个顶点到其他各顶点的距离
        public int[][] pre;    //  存放到达目标顶点的前驱节点
    
        /**
         * 初始化顶点,dis,pre
         * @param vertexes
         * @param matrix
         * @param length
         */
        public FGraph(char[] vertexes, int[][] matrix, int length) {
            this.vertexes = vertexes;
            this.dis = matrix;
            /*对pre数组进行初始化,存放的是前驱节点的下标*/
            this.pre = new int[length][length];
            for (int i = 0; i < length; i++) {
                Arrays.fill(pre[i], i);
            }
    
        }
    
    
        public void show() {
            for(int k = 0; k < dis.length;k++){
    
                // 输出pre
                for (int j = 0; j < dis.length; j++) {
                    System.out.print(vertexes[pre[k][j]] + " ");
                }
                System.out.println();
                // 输出dis
                for (int i = 0; i < dis.length; i++) {
                    System.out.print("(" + vertexes[k] + "到"+vertexes[i]+"的最短路径是: " + dis[k][i] + ") ");
                }
                System.out.println();
            }
        }
    }

      实现算法(vki+vkj < vij)

     public void floyd(){
            int len = 0; // 保存距离
            /*对中间节点进行遍历,k就是中间节点的下标 [A, B, C, D, E, F, G] */
            for (int k = 0; k < dis.length; k++) {
                /*从i顶点开始出发 [A, B, C, D, E, F, G] */
                for (int i = 0; i < dis.length; i++) {
                    /*到达j顶点 [A, B, C, D, E, F, G] */
                    for (int j = 0; j < dis.length; j++) {
                        /*计算出从i出发,经过k中间节点,到达j的距离*/
                        len = dis[i][k] + dis[k][j];
                        if (len < dis[i][j]) {/*如果len小于原本的距离*/
                            /*更新距离表*/
                            dis[i][j] = len;
                            /*更新前驱节点*/
                            pre[i][j] = pre[k][j];
                        }
                    }
                }
            }
        }

    执行结果:

           

     

      

  • 相关阅读:
    python汉诺塔
    圆周率计算
    PIL: 建立一个GIF图
    Jieba库使用和好玩的词云
    Turtle库的建立——汉诺塔
    计算pi的精度+进度条显示
    Python——我所学习的turtle函数库
    Python——教你画朵太阳花
    Python常用模块re的使用
    正则表达式字符组/元字符/量词
  • 原文地址:https://www.cnblogs.com/luhuajun/p/12354945.html
Copyright © 2020-2023  润新知