• Java数据结构 最短路径解法Dijkstra算法



      本文为博主原创文章,未经博主允许不得转载!

    1.1、定义概览
    Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。

    问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)

    1.2、算法描述
    1)算法思想:设G=(V,E)是一个带权有向图,把图中顶点集合V分成两组,第一组为已求出最短路径的顶点集合(用S表示,初始时S中只有一个源点,以后每求得一条最短路径 , 就将加入到集合S中,直到全部顶点都加入到S中,算法就结束了),第二组为其余未确定最短路径的顶点集合(用U表示),按最短路径长度的递增次序依次把第二组的顶点加入S中。在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到U中任何顶点的最短路径长度。此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,U中的顶点的距离,是从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。

    2)算法步骤:
    a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
    b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
    c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
    d.重复步骤b和c直到所有顶点都包含在S中。

    实现:

      1 public class GraphByMatrix {  
      2     public static final boolean UNDIRECTED_GRAPH = false;//无向图标志  
      3     public static final boolean DIRECTED_GRAPH = true;//有向图标志  
      4   
      5     public static final boolean ADJACENCY_MATRIX = true;//邻接矩阵实现  
      6     public static final boolean ADJACENCY_LIST = false;//邻接表实现  
      7   
      8     public static final int MAX_VALUE = Integer.MAX_VALUE;  
      9     private boolean graphType;  
     10     private boolean method;  
     11     private int vertexSize;  
     12     private int matrixMaxVertex;  
     13   
     14     //存储所有顶点信息的一维数组  
     15     private Object[] vertexesArray;  
     16     //存储图中顶点之间关联关系的二维数组,及边的关系  
     17     private int[][] edgesMatrix;  
     18   
     19     // 记录第i个节点是否被访问过  
     20     private boolean[] visited;  
     21   
     22     /** 
     23      * @param graphType 图的类型:有向图/无向图 
     24      * @param method    图的实现方式:邻接矩阵/邻接表 
     25      */  
     26     public GraphByMatrix(boolean graphType, boolean method, int size) {  
     27         this.graphType = graphType;  
     28         this.method = method;  
     29         this.vertexSize = 0;  
     30         this.matrixMaxVertex = size;  
     31   
     32         if (this.method) {  
     33             visited = new boolean[matrixMaxVertex];  
     34             vertexesArray = new Object[matrixMaxVertex];  
     35             edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex];  
     36   
     37             //对数组进行初始化,顶点间没有边关联的值为Integer类型的最大值  
     38             for (int row = 0; row < edgesMatrix.length; row++) {  
     39                 for (int column = 0; column < edgesMatrix.length; column++) {  
     40                     edgesMatrix[row][column] = MAX_VALUE;  
     41                 }  
     42             }  
     43   
     44         }  
     45     }  
     46   
     47     /********************最短路径****************************/  
     48     //计算一个顶点到其它一个顶点的最短距离  
     49     public void Dijkstra(Object obj) throws Exception {  
     50         Dijkstra(getVertexIndex(obj));  
     51     }  
     52     public void Dijkstra(int v0) {  
     53         int[] dist = new int[matrixMaxVertex];  
     54         int[] prev = new int[matrixMaxVertex];  
     55   
     56         //初始化visited、dist和path  
     57         for (int i = 0; i < vertexSize; i++) {  
     58             //一开始假定取直达路径最短  
     59             dist[i] = edgesMatrix[v0][i];  
     60             visited[i] = false;  
     61   
     62             //直达情况下的最后经由点就是出发点  
     63             if (i != v0 && dist[i] < MAX_VALUE)  
     64                 prev[i] = v0;  
     65             else  
     66                 prev[i] = -1; //无直达路径  
     67         }  
     68   
     69         //初始时源点v0∈visited集,表示v0 到v0的最短路径已经找到  
     70         visited[v0] = true;  
     71   
     72         // 下来假设经由一个点中转到达其余各点,会近些,验证之  
     73         // 再假设经由两个点中转,会更近些,验证之,.....  
     74         // 直到穷举完所有可能的中转点  
     75         int minDist;  
     76         int v = 0;  
     77         for (int i = 1; i < vertexSize; i++) {  
     78             //挑一个距离最近经由点,下标装入 v  
     79             minDist = MAX_VALUE;  
     80   
     81             for (int j = 0; j < vertexSize; j++) {  
     82                 if ((!visited[j]) && dist[j] < minDist) {  
     83                     v = j;                             // 经由顶点j中转则距离更短  
     84                     minDist = dist[j];  
     85                 }  
     86             }  
     87             visited[v] = true;  
     88   
     89             /*顶点v并入S,由v0到达v顶点的最短路径为min. 
     90               假定由v0到v,再由v直达其余各点,更新当前最后一个经由点及距离*/  
     91             for (int j = 0; j < vertexSize; j++) {  
     92                 if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) {  
     93   
     94                     if (minDist + edgesMatrix[v][j] <= dist[j]) {  
     95                         //如果多经由一个v点到达j点的 最短路径反而要短,就更新  
     96                         dist[j] = minDist + edgesMatrix[v][j];  
     97   
     98                         prev[j] = v;                    //经由点的序号  
     99                     }  
    100   
    101                 }  
    102             }  
    103   
    104         }  
    105   
    106         for (int i = 1; i < matrixMaxVertex; i++) {  
    107             System.out.println("**" + vertexesArray[v0] + "-->" +vertexesArray[i] + " 的最短路径是:" + dist[i]);  
    108         }  
    109     }  
    110   
    111     //获取顶点值在数组里对应的索引  
    112     private int getVertexIndex(Object obj) throws Exception {  
    113         int index = -1;  
    114         for (int i = 0; i < vertexSize; i++) {  
    115             if (vertexesArray[i].equals(obj)) {  
    116                 index = i;  
    117                 break;  
    118             }  
    119         }  
    120         if (index == -1) {  
    121             throw new Exception("没有这个值!");  
    122         }  
    123   
    124         return index;  
    125     }  
    126   
    127     /** 
    128      * 单源最短路径算法,用于计算一个节点到其他!!所有节点!!的最短路径 
    129      */  
    130     public void Dijkstra2(int v0) {  
    131         // LinkedList实现了Queue接口 FIFO  
    132         Queue<Integer> queue = new LinkedList<Integer>();  
    133         for (int i = 0; i < vertexSize; i++) {  
    134             visited[i] = false;  
    135         }  
    136   
    137         //这个循环是为了确保每个顶点都被遍历到  
    138         for (int i = 0; i < vertexSize; i++) {  
    139             if (!visited[i]) {  
    140                 queue.add(i);  
    141                 visited[i] = true;  
    142   
    143                 while (!queue.isEmpty()) {  
    144                     int row = queue.remove();  
    145                     System.out.print(vertexesArray[row] + "-->");  
    146   
    147                     for (int k = getMin(row); k >= 0; k = getMin(row)) {  
    148                         if (!visited[k]) {  
    149                             queue.add(k);  
    150                             visited[k] = true;  
    151                         }  
    152                     }  
    153   
    154                 }  
    155             }  
    156         }  
    157     }  
    158   
    159     private int getMin( int row) {  
    160         int minDist = MAX_VALUE;  
    161         int index = 0;  
    162         for (int j = 0; j < vertexSize; j++) {  
    163             if ((!visited[j]) && edgesMatrix[row][j] < minDist) {  
    164                 minDist = edgesMatrix[row][j];  
    165                 index = j;  
    166             }  
    167         }  
    168         if (index == 0) {  
    169             return -1;  
    170         }  
    171         return index;  
    172     }  
    173   
    174     public boolean addVertex(Object val) {  
    175         assert (val != null);  
    176         vertexesArray[vertexSize] = val;  
    177         vertexSize++;  
    178         return true;  
    179     }  
    180   
    181     public boolean addEdge(int vnum1, int vnum2, int weight) {  
    182         assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2 && weight >= 0);  
    183   
    184         //有向图  
    185         if (graphType) {  
    186             edgesMatrix[vnum1][vnum2] = weight;  
    187   
    188         } else {  
    189             edgesMatrix[vnum1][vnum2] = weight;  
    190             edgesMatrix[vnum2][vnum1] = weight;  
    191         }  
    192   
    193         return true;  
    194     }  
    195   
    196 }  

    测试

     1 @Test  
     2 public void testWeight() throws Exception {  
     3     GraphByMatrix graph = new GraphByMatrix(Graph.UNDIRECTED_GRAPH, Graph.ADJACENCY_MATRIX, 6);  
     4   
     5     graph.addVertex("1");  
     6     graph.addVertex("2");  
     7     graph.addVertex("3");  
     8     graph.addVertex("4");  
     9     graph.addVertex("5");  
    10     graph.addVertex("6");  
    11   
    12     graph.addEdge(0, 1,7);  
    13     graph.addEdge(0, 2,9);  
    14     graph.addEdge(0, 5,14);  
    15   
    16     graph.addEdge(1, 3,15);  
    17     graph.addEdge(1, 2,10);  
    18   
    19     graph.addEdge(2, 3,11);  
    20     graph.addEdge(2, 5,2);  
    21   
    22     graph.addEdge(3, 4,6);  
    23     graph.addEdge(4, 5,9);  
    24   
    25     graph.Dijkstra(0);  
    26     System.out.println();  
    27     graph.Dijkstra("1");  
    28     System.out.println();  
    29     graph.Dijkstra2(0);  
    30     System.out.println();  
    31 }  
  • 相关阅读:
    CMSIS-SVD Reference
    CMSIS-SVD 系统视图说明
    Git 中文件的状态和流转区
    Windows下配置Git服务器和客户端
    gitignore / Delphi.gitignore
    gitignore : VisualStudio.gitignore
    使用 VS2012 开发 IDA GUI 插件 WIN32 SDK 和 内置函数 AskUsingForm_c
    stdafx.h是什么用处, stdafx.h、stdafx.cpp的作用
    [Win32]创建模态窗口
    Process ID, Process handle, Window handle
  • 原文地址:https://www.cnblogs.com/frankdevhub/p/7401088.html
Copyright © 2020-2023  润新知