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();
|
}
|
|
}
|