package com.doumee.core.utils; 
 | 
  
 | 
import java.util.*; 
 | 
  
 | 
/** 
 | 
 * 最短路径—Dijkstra算法和Floyd算法 
 | 
 * Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。注意该算法要求图中不存在负权边。 
 | 
 * 
 | 
 * 问题描述:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径) 
 | 
 */ 
 | 
  
 | 
public class GraphByMatrix { 
 | 
    public static final boolean UNDIRECTED_GRAPH = false;//无向图标志 
 | 
    public static final boolean DIRECTED_GRAPH = true;//有向图标志 
 | 
  
 | 
    public static final boolean ADJACENCY_MATRIX = true;//邻接矩阵实现 
 | 
    public static final boolean ADJACENCY_LIST = false;//邻接表实现 
 | 
  
 | 
    public static final int MAX_VALUE = Integer.MAX_VALUE; 
 | 
    private boolean graphType; 
 | 
    private boolean method; 
 | 
    private int vertexSize; 
 | 
    private int matrixMaxVertex; 
 | 
  
 | 
    //存储所有顶点信息的一维数组 
 | 
    private Object[] vertexesArray; 
 | 
    //存储图中顶点之间关联关系的二维数组,及边的关系 
 | 
    private int[][] edgesMatrix; 
 | 
  
 | 
    // 记录第i个节点是否被访问过 
 | 
    private boolean[] visited; 
 | 
  
 | 
    /** 
 | 
     * @param graphType 图的类型:有向图/无向图 
 | 
     * @param method    图的实现方式:邻接矩阵/邻接表 
 | 
     */ 
 | 
    public GraphByMatrix(boolean graphType, boolean method, int size) { 
 | 
        this.graphType = graphType; 
 | 
        this.method = method; 
 | 
        this.vertexSize = 0; 
 | 
        this.matrixMaxVertex = size; 
 | 
  
 | 
        if (this.method) { 
 | 
            visited = new boolean[matrixMaxVertex]; 
 | 
            vertexesArray = new Object[matrixMaxVertex]; 
 | 
            edgesMatrix = new int[matrixMaxVertex][matrixMaxVertex]; 
 | 
  
 | 
            //对数组进行初始化,顶点间没有边关联的值为Integer类型的最大值 
 | 
            for (int row = 0; row < edgesMatrix.length; row++) { 
 | 
                for (int column = 0; column < edgesMatrix.length; column++) { 
 | 
                    edgesMatrix[row][column] = MAX_VALUE; 
 | 
                } 
 | 
            } 
 | 
  
 | 
        } 
 | 
    } 
 | 
  
 | 
    /********************最短路径****************************/ 
 | 
    //计算一个顶点到其它一个顶点的最短距离 
 | 
    public void Dijkstra(Object obj) throws Exception { 
 | 
        Dijkstra(getVertexIndex(obj)); 
 | 
    } 
 | 
    public void Dijkstra(int v0) { 
 | 
        int[] dist = new int[matrixMaxVertex]; 
 | 
        int[] prev = new int[matrixMaxVertex]; 
 | 
  
 | 
        //初始化visited、dist和path 
 | 
        for (int i = 0; i < vertexSize; i++) { 
 | 
            //一开始假定取直达路径最短 
 | 
            dist[i] = edgesMatrix[v0][i]; 
 | 
            visited[i] = false; 
 | 
  
 | 
            //直达情况下的最后经由点就是出发点 
 | 
            if (i != v0 && dist[i] < MAX_VALUE) 
 | 
                prev[i] = v0; 
 | 
            else 
 | 
                prev[i] = -1; //无直达路径 
 | 
        } 
 | 
  
 | 
        //初始时源点v0∈visited集,表示v0 到v0的最短路径已经找到 
 | 
        visited[v0] = true; 
 | 
  
 | 
        // 下来假设经由一个点中转到达其余各点,会近些,验证之 
 | 
        // 再假设经由两个点中转,会更近些,验证之,..... 
 | 
        // 直到穷举完所有可能的中转点 
 | 
        int minDist; 
 | 
        int v = 0; 
 | 
        for (int i = 1; i < vertexSize; i++) { 
 | 
            //挑一个距离最近经由点,下标装入 v 
 | 
            minDist = MAX_VALUE; 
 | 
  
 | 
            for (int j = 0; j < vertexSize; j++) { 
 | 
                if ((!visited[j]) && dist[j] < minDist) { 
 | 
                    v = j;                             // 经由顶点j中转则距离更短 
 | 
                    minDist = dist[j]; 
 | 
                } 
 | 
            } 
 | 
            visited[v] = true; 
 | 
  
 | 
            /*顶点v并入S,由v0到达v顶点的最短路径为min. 
 | 
              假定由v0到v,再由v直达其余各点,更新当前最后一个经由点及距离*/ 
 | 
            for (int j = 0; j < vertexSize; j++) { 
 | 
                if ((!visited[j]) && edgesMatrix[v][j] < MAX_VALUE) { 
 | 
  
 | 
                    if (minDist + edgesMatrix[v][j] <= dist[j]) { 
 | 
                        //如果多经由一个v点到达j点的 最短路径反而要短,就更新 
 | 
                        dist[j] = minDist + edgesMatrix[v][j]; 
 | 
  
 | 
                        prev[j] = v;                    //经由点的序号 
 | 
                    } 
 | 
  
 | 
                } 
 | 
            } 
 | 
  
 | 
        } 
 | 
  
 | 
        for (int i = 1; i < matrixMaxVertex; i++) { 
 | 
            System.out.println("**" + vertexesArray[v0] + "-->" +vertexesArray[i] + " 的最短路径是:" + dist[i]); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    //获取顶点值在数组里对应的索引 
 | 
    private int getVertexIndex(Object obj) throws Exception { 
 | 
        int index = -1; 
 | 
        for (int i = 0; i < vertexSize; i++) { 
 | 
            if (vertexesArray[i].equals(obj)) { 
 | 
                index = i; 
 | 
                break; 
 | 
            } 
 | 
        } 
 | 
        if (index == -1) { 
 | 
            throw new Exception("没有这个值!"); 
 | 
        } 
 | 
  
 | 
        return index; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * 单源最短路径算法,用于计算一个节点到其他!!所有节点!!的最短路径 
 | 
     */ 
 | 
    public void Dijkstra2(int v0) { 
 | 
        // LinkedList实现了Queue接口 FIFO 
 | 
        Queue<Integer> queue = new LinkedList<>(); 
 | 
        for (int i = 0; i < vertexSize; i++) { 
 | 
            visited[i] = false; 
 | 
        } 
 | 
        List<Map<String,Object>> result = new ArrayList<>(); 
 | 
        //这个循环是为了确保每个顶点都被遍历到 
 | 
        int lastRow =0; 
 | 
        for (int i = 0; i < vertexSize; i++) { 
 | 
            if (!visited[i]) { 
 | 
                queue.add(i); 
 | 
                visited[i] = true; 
 | 
                while (!queue.isEmpty()) { 
 | 
                    int row = queue.remove(); 
 | 
                    Map<String,Object> map = new HashMap<>(); 
 | 
                    map.put("name", vertexesArray[row]); 
 | 
                    map.put("row", row); 
 | 
                    int tempDis =0; 
 | 
                    if(row>0){ 
 | 
                        tempDis  = edgesMatrix[lastRow][row]; 
 | 
                        lastRow =row; 
 | 
                    } 
 | 
                    map.put("dis", tempDis); 
 | 
                    result.add(map); 
 | 
                    System.out.print(vertexesArray[row] + "-->"); 
 | 
                    for (int k = getMin(row); k >= 0; k = getMin(row)) { 
 | 
                        if (!visited[k]) { 
 | 
                            queue.add(k); 
 | 
                            visited[k] = true; 
 | 
                        } 
 | 
                    } 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
        System.out.println(""); 
 | 
        int totalDis =0; 
 | 
        for(Map<String,Object> c :result){ 
 | 
            totalDis +=  (Integer) c.get("dis"); 
 | 
            System.out.print( c.get("name") + "--"+c.get("dis")+"-->"); 
 | 
        } 
 | 
        System.out.println(""); 
 | 
        System.out.println("最短距离"+totalDis); 
 | 
    } 
 | 
  
 | 
    private int getMin( int row) { 
 | 
        int minDist = MAX_VALUE; 
 | 
        int index = 0; 
 | 
        for (int j = 0; j < vertexSize; j++) { 
 | 
            if ((!visited[j]) && edgesMatrix[row][j] < minDist) { 
 | 
                minDist = edgesMatrix[row][j]; 
 | 
                index = j; 
 | 
            } 
 | 
        } 
 | 
        if (index == 0) { 
 | 
            return -1; 
 | 
        } 
 | 
        return index; 
 | 
    } 
 | 
  
 | 
    public boolean addVertex(Object val) { 
 | 
        assert (val != null); 
 | 
        vertexesArray[vertexSize] = val; 
 | 
        vertexSize++; 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    public boolean addEdge(int vnum1, int vnum2, int weight) { 
 | 
        assert (vnum1 >= 0 && vnum2 >= 0 && vnum1 != vnum2 && weight >= 0); 
 | 
  
 | 
        //有向图 
 | 
        if (graphType) { 
 | 
            edgesMatrix[vnum1][vnum2] = weight; 
 | 
  
 | 
        } else { 
 | 
            edgesMatrix[vnum1][vnum2] = weight; 
 | 
            edgesMatrix[vnum2][vnum1] = weight; 
 | 
        } 
 | 
  
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    public static void main(String[] args) throws Exception { 
 | 
        GraphByMatrix graph = new GraphByMatrix(GraphByMatrix.DIRECTED_GRAPH, GraphByMatrix.ADJACENCY_MATRIX, 9); 
 | 
  
 | 
        graph.addVertex("A");//0 
 | 
        graph.addVertex("B");//1 
 | 
        graph.addVertex("C");//2 
 | 
        graph.addVertex("D");//3 
 | 
        graph.addVertex("E");//4 
 | 
  
 | 
        //A->B、C、D 
 | 
        graph.addEdge(0, 1,10); 
 | 
        graph.addEdge(0, 2,5); 
 | 
        graph.addEdge(0, 3,7); 
 | 
        //B->C、D、E 
 | 
        graph.addEdge(1, 2,4); 
 | 
        graph.addEdge(1, 3,5); 
 | 
        graph.addEdge(1, 4,10); 
 | 
        //C->B、D、E 
 | 
        graph.addEdge(2, 1,4); 
 | 
        graph.addEdge(2, 3,6); 
 | 
        graph.addEdge(2, 4,5); 
 | 
        //D->B、C、E 
 | 
        graph.addEdge(3, 1,5); 
 | 
        graph.addEdge(3, 2,6); 
 | 
        graph.addEdge(3, 4,7); 
 | 
  
 | 
  
 | 
        graph.Dijkstra(0); 
 | 
        System.out.println(); 
 | 
        graph.Dijkstra("C"); 
 | 
        System.out.println(); 
 | 
        graph.Dijkstra2(0); 
 | 
        System.out.println(); 
 | 
    } 
 | 
  
 | 
} 
 |