您的位置:首页 > 编程语言 > Java开发

最短路径-Dijkstra

2017-05-12 15:29 246 查看
首先,提出两点:一、如果把不带权图上的所有边的权值均定义为1,则该不带权图可以归结为带权图;二、如果把无向图中的每一条边(vi,vj)都定义为弧<vi,vj>和弧<vj,vi>,则该无向图可以归结为有向图。因此不失一般性,我们只用看有向带权图怎么求解最短路径问题就ok。

带权图中,从一个结点到另个一结点存在着多条路径,称每一条路径上所经过边的权值之和为该路径上的带权路径长度,那么在两个结点间的所有路径中,路径长度值最小的称做最短路径(距离)。

对于有向带权图中从一个确定结点(源点)到其余各结点的最短路径问题,狄克斯特拉(Dijkstra)提出了一个按照路径长度递增的顺序逐步产生最短路径的构造算法。

Dijkstra算法:设置两个结点的集合S和T,集合S中存放已找到最短路径的结点,集合T存放当前还未找到最短路径的结点。(1)初始状态,S只包含源点,设为v0;(2)然后从T中选择出由源点v0到其中某一结点路径长度最短的结点u,加入到集合S中;(3)集合S中每加入一个新的结点u都要修改源点v0到集合T中剩余结点的当前最短路径长度值;(4)那么这最小的当前最短路径长度值为,原来的当前最短路径长度值和从源点v0过结点u到到达该结点的路径长度相比,取小的那个值。(5)不断重复,知道集合T中的结点全部加入到集合S中为止。

接下来实现算法:

package Map;
/**
* @author sun
* 创建时间:2017年5月11日下午5:02:17
*/
//dijkstra类和函数设计
public class Dijkstra {
static final int maxWeight = 9999;
public static void dijkstra(AdjMWGraph g,int v0,int[] distance,int[] path)throws Exception{
//带权图g从下标v0结点到其他结点的最短距离distance
//和相应的目标结点的前一结点下标path
int n = g.getNumOfVertices();
int[] s = new int
;//s用来存放n个结点的标记
int minDis,u=0;//u为目标结点下标
//初始化
for(int i=0;i<n;i++){
distance[i] = g.getWeight(v0, i);
s[i] = 0;//初始标记为0
if(i!=v0 && distance[i]<maxWeight)
path[i] = v0;//初始的目标结点的前一结点均为v0
else
path[i] = -1;
}
s[v0] = 1;//标记结点v0已从集合T加入到集合S中

//在当前还未找到最短路径的结点集合中选取具有最短距离的结点u
for(int i=1;i<n;i++){
minDis = maxWeight;
for(int j=0;j<n;j++)
if(s[j]==0 && distance[j]<minDis){
u = j;
minDis = distance[j];
}
//当已不存在路径时算法结束;此语句对非连通图是必需的
if(minDis==maxWeight) return;

s[u] = 1;//标记结点u已从集合T加入到集合S中
//修改从v0到其他结点的最短距离和最短路径
for(int j=0;j<n;j++)
if(s[j]==0 && g.getWeight(u, j)<maxWeight && distance[u]
+g.getWeight(u, j)<distance[j]){
//结点v0经结点u到其他结点的最短距离和最短路径
distance[j] = distance[u]+g.getWeight(u, j);
path[j] = u;
}
}
}
}


对下图进行测试:



package Map;
/**
* @author sun
* 创建时间:2017年5月11日下午5:39:55
*/
public class TestDijkstra {
static final int maxVertices = 100;
//构造图
public static void createGraph(AdjMWGraph g,Object[] v,int n
,RowColWeight[] rc,int e)throws Exception{
for(int i=0;i<n;i++)
g.insertVertex(v[i]);
for(int k=0;k<e;k++)
g.inserEdge(rc[k].row,rc[k].col, rc[k].weight);
}

public static void main(String[] args) {
AdjMWGraph g = new AdjMWGraph(maxVertices);
Character[] a = {new Character('A'),new Character('B'),
new Character('C'),new Character('D'),
new Character('E'),new Character('F')};
RowColWeight[] rcw = {new RowColWeight(0,2,5),new RowColWeight(0,3,30),
new RowColWeight(1,0,2),new RowColWeight(1,4,8),new RowColWeight(2,1,15),
new RowColWeight(2,5,7),new RowColWeight(4,3,4),new RowColWeight(5,3,10),
new RowColWeight(5,4,18)};
int n = 6,e = 9;
try{
createGraph(g,a,n,rcw,e);
int[] distance = new int
;
int[] path = new int
;
Dijkstra.dijkstra(g, 0, distance, path);
System.out.println("从顶点A到其他各顶点的最短距离为: ");
for(int i=1;i<n;i++)
System.out.println("到顶点"+g.getValue(i)+"的最短距离为:"+distance[i]);
System.out.println("从顶点A到其他各顶点的前一顶点分别为:");
for(int i=0;i<n;i++)
if(path[i]!=-1)
System.out.println("到顶点"+g.getValue(i)+"的前一顶点为:"+g.getValue(path[i]));
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
/*
从顶点A到其他各顶点的最短距离为:
到顶点B的最短距离为:20
到顶点C的最短距离为:5
到顶点D的最短距离为:22
到顶点E的最短距离为:28
到顶点F的最短距离为:12
从顶点A到其他各顶点的前一顶点分别为:
到顶点B的前一顶点为:C
到顶点C的前一顶点为:A
到顶点D的前一顶点为:F
到顶点E的前一顶点为:B
到顶点F的前一顶点为:C
*/

求每对结点之间的最短路径,若利用Dijkstra算法(时间复杂度为O(n^2)),就是每次以不同的结点作为源点,求解该源点到其余结点的最短路径。那么,求该问题的算法时间复杂度为O(n^3)。
对于此问题,弗洛伊德(Floyd)提出了一种递推的算法来求解,即弗洛伊德算法。

用矩阵cost[i][j]来存放图G中下标为i的结点到下标为j的结点之间的权值,那么可以通过递推构造一个矩阵序列A0,A1,···,AN来求每对结点之间的最短路径。其中,Ak[i][j](0<k<n)表示从结点vi到结点vj的路径上所经过的结点下标不大于k的最短路径长度。

弗洛伊德算法的思想可用地推公式描述:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java 最短路径