寻找两个顶点之间的最短路径
规则,总是派遣一个代理人到下一个城市,代理人的工作是记录源点到其它城市费用最小信息。
计算费用,构造一个数组,保持从源点到其他顶点的最短距离。在算法执行的过程中这个距离是变化的。直到最后,它存储了从源点开始的真正最短距离。
package com.mapbar.structure;
/**
* Class Graph_Dijkstra.java
* Description Dijkstra 最短路径算法,用数组替代优先级队列来存储最短距离
* Company mapbar
* author Chenll E-mail: Chenll@mapbar.com
* Version 1.0
* Date 2012-8-30 下午03:46:15
*/
//保存从起始点到当前点的距离以及父节点
class DistPar{
public int distance;
public int parVert;
public DistPar(int pv, int dis){
this.distance = dis;
this.parVert = pv;
}
}
//定义顶点
class Vertex{
public char label;
public boolean isInTree;
public Vertex(char label){
this.label = label;
isInTree = false;
}
}
class Graph{
private final int MAX_VERTX = 20; //节点数
private final int INFINITY = 1000000; //最远距离
private Vertex vertexList[];
private int adjMat[][]; //邻接矩阵
private int nVerts; //记录顶点的个数
private int nTree; //记录树中顶点的个数
private int currentVert; //当前顶点
private DistPar sPath[];//最短路径数组,存储源点到其它顶点距离情况。
private int startToCurrent;
//构造方法
public Graph() {
vertexList = new Vertex[MAX_VERTX];
adjMat = new int[MAX_VERTX][MAX_VERTX];
nVerts = 0;
// 初始化矩阵
for (int i = 0; i < MAX_VERTX; i++) {
for (int j = 0; j < MAX_VERTX; j++) {
adjMat[i][j] = INFINITY;
}
}
sPath = new DistPar[MAX_VERTX];
}
// 添加顶点
public void addVertex(char label) {
vertexList[nVerts++] = new Vertex(label);
}
// 添加边
public void addEdge(int sv, int dv, int dis) {
adjMat[sv][dv] = dis;
}
//路径规划
public void path(){
int startTree = 0;
vertexList[0].isInTree = true;
nTree = 1;
for(int i = 0; i<nVerts; i++){
int tempDis = adjMat[startTree][i];
sPath[i] = new DistPar(startTree,tempDis);
}
while(nTree < nVerts){
//(1)找到sPath数组中最小的距离
int indexMin= getMin();
int minDis = sPath[indexMin].distance;
if(minDis == INFINITY){
break;
} else {
//(2) 设置当前顶点
currentVert = indexMin;
//源点到当前顶点的最短距离
startToCurrent = sPath[indexMin].distance;
}
vertexList[currentVert].isInTree = true;
nTree ++;
//(3)根据当前顶点变化,调整数组
adjust_sPath();
}
displayPath();
//重置
nTree = 0;
for(int j = 0; j<nVerts; j++){
vertexList[j].isInTree = false;
}
}
//找到sPath[i]数组中未在树中并且距离最小的顶点
public int getMin(){
int minDis = INFINITY;
int indexMin = 0;
for(int i = 1; i<nVerts; i++){
if(!vertexList[i].isInTree && sPath[i].distance < minDis){
minDis = sPath[i].distance;
indexMin = i;
}
}
return indexMin;
}
//根据当前顶点调整距离数组的值
public void adjust_sPath(){
//循环计数器,依次指向每个顶点
int column = 1;
while (column < nVerts){
if(vertexList[column].isInTree){
column ++;
continue;
}
int currentToFringe = adjMat[currentVert][column];
int startToFring = currentToFringe + startToCurrent;
int sPathDis= sPath[column].distance;
if(startToFring < sPathDis){
//替换当前项,让数组总是存储从源点到所有已知顶点最短路径
sPath[column].parVert = currentVert;
sPath[column].distance = startToFring;
}
column ++;
}
}
//显示数组就是源点到各个顶点的最短距离括号里面是父节点
public void displayPath(){
for(int j = 0; j<nVerts; j++){
System.out.print(vertexList[j].label+"=");
if(sPath[j].distance == INFINITY){
System.out.print("INF");
} else {
System.out.print(sPath[j].distance);
}
char parent = vertexList[sPath[j].parVert].label;
System.out.print("("+parent+") ");
}
}
}
public class Graph_Dijkstra {
public static void main(String[] args){
Graph g = new Graph();
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addVertex('D');
g.addVertex('E');
g.addEdge(0, 1, 50);
g.addEdge(0, 3, 80);
g.addEdge(1, 2, 60);
g.addEdge(1, 3, 90);
g.addEdge(2, 4, 40);
g.addEdge(3, 2, 20);
g.addEdge(3, 4, 70);
g.addEdge(4, 1, 50);
g.path();
}
}
输出结果:A=INF(A) B=50(A) C=100(D) D=80(A) E=140(C)