您的位置:首页 > 其它

Dijkstra算法求图的单源最短路径

2012-12-04 13:08 357 查看
源码下载:http://download.csdn.net/detail/nuptboyzhb/4848125

简介:

Dijkstra算法是已知网络的拓扑结构和各链路的长度,寻找从源节点到网络中其他各节点的最短路径。

设某个节点为源节点,每次寻找一个节点到源节点的最短路径,直至找到所有的节点。

以网络中的每一个节点作为源节点,分别使用最短路径算法,得出的结果就是全网的最短路径。

一. 图的表示和存储

在学习数据结构中,我们都知道,图有2种常见的表示形式:邻接矩阵和邻接表。如下图[1][2]所示





[图1] [图2]

对于无向图,如下图:它的连接矩阵的表示形式是一个实对称矩阵。如图3



[图3]

对于有向图,如下图表示:



图4

编程约定:

在编程时,我们通常有一下几种方法来代替无穷大

a.用一个很大的数来代替(比任何边的和都大)

b.用-1代替。图中的权值都不为负数,如果检查到负数,那么就知道它们之间没有直接相连

二. Dijkstra算法的步骤

设L(i,j)为i点与j点的权值

设L(i,j)为i点与j点的权值

1.初始化

设节点1为源节点,令N为已寻找到最短路径网络节点集合,N={1};

对所有不在N中的节点,有:

D(v)= L(i,j) ;若节点v与节点1直接相连

D(v)=∞;若节点v与节点1不直接相连

2.寻找一个不在N中的节点w,其D(w)值最小,把w加入到N中,然后对所有不在N中的节点v,

a.v节点之前与w不相邻(即D(v)=∞):

则D(v)更新为:D(v)=D(w)+L(w,v);

b.D(v)!=∞

则用[ D(v),D(w)+ L(w,v)]中较小的值去更新原有的D(v)值,即:

D(v)←Min[ D(v),D(w)+ L(w,v)] 。

3.重复步骤2,直至所有网络节点都在N中为止(循环次数=节点数)。

对图三中的迭代过程:



三. Dijkstra算法的实现

JAVA版本代码

/*
*@author: ZhengHaibo
*web:     blog.csdn.net/nuptboyzhb
*mail:    zhb931706659@126.com
*2012-12-4  Nanjing njupt
*/
public class DijkstraTest{
public static void outPutMinPath(int []preIndex,int start,int end,int len)
{
int []path=new int[len];//定义存放路径的数组
int i=end;
path[0]=i;
int k=1;
while (preIndex[i]!=start) {
i=preIndex[i];
path[k]=i;//反向遍历
k++;
}
path[k]=start;
for (int j = k; j >0; j--) {
System.out.print("V"+path[j]+"->");
}
System.out.println("V"+path[0]);
}
//查找权值为L1矩阵,起始点到终点的最短路径和最短距离
public static int dijkstra(int[][] L1, int start, int end) {
boolean[] isLabel = new boolean[L1[0].length];// 是否标号
int[] N = new int[L1[0].length];// 所有标号的点的下标集合,以标号的先后顺序进行存储,实际上是一个以数组表示的栈
//int[] zhb_router =new int[L1[0].length];
int count = 0;//被标号顶点的顺序或数目
int[] Distance = L1[start].clone();// v0到各点的最短距离的初始值
int index = start;// 从初始点开始
N[count] = index;// 把已经标号的下标存入下标集中
int []preIndex=new int[L1[0].length];//用于记录最短路径树中的节点的前一个节点序号
for (int i = 0; i < preIndex.length; i++) {//初始化为起始接点
preIndex[i]=start;
}
isLabel[index] = true;
while (count<L1[0].length){
// 第一步:标号v_start,即w[start][0]行中找到距离v_start最近的点
int min = Integer.MAX_VALUE;
//找出与v_start距离最短的Distance的下标
for (int i = 0; i < Distance.length; i++) {
if (!isLabel[i] && Distance[i] != -1 && i != index) {
// 如果到这个点有边,并且没有被标号
if (Distance[i] < min) {
min = Distance[i];
index = i;// 记录下这个下标
}
}
}
if (index == end) {//已经找到当前点了,就结束查找
break;
}
isLabel[index] = true;//对点进行标号
count++;//增加一个标定的点
N[count] = index;// 把已经标号的下标存入下标集中
// 第二步:加入新的节点后,更新所有不在N中的节点的Distance
for (int i = 0; i < Distance.length; i++) {
//这个节点原来不可到达,刚加入的点和这个节点是互联的,并且不在N中
if (Distance[i] == -1 && L1[index][i] != -1&&!isLabel[i]) {//如果以前不可达,则现在可达了
Distance[i] = Distance[index] + L1[index][i];
preIndex[i]=index;//更新最短路径中当前接点的前一个接点
} else if (L1[index][i] != -1 && Distance[index] + L1[index][i] < Distance[i]) {
// 如果以前可达,但现在的路径比以前更短,则更换成更短的路径
//即先从
Distance[i] = Distance[index] + L1[index][i];
preIndex[i]=index;//更新最短路径中当前接点的前一个接点
}
}//每个节点到起始节点的最小距离更新完毕
}
//如果全部点都遍历完,则Distance中存储的是开始点到各个点的最短路径
System.out.println("节点v"+start+"到节点v"+end+"的短距离为:"+(Distance[end]-Distance[start]));
outPutMinPath(preIndex,start,end,Distance.length);
return Distance[end];
}
//查找权值为L1矩阵,起始点到所有点的最短路径和最短距离
//它与上面的Dijkstra函数的终止条件不同,这个是遍历所有节点后才结束
//而上面的算法只需要找到结束点end即结束。
public static void dijkstra(int[][] L1, int start) {
boolean[] isLabel = new boolean[L1[0].length];// 是否标号
int[] N = new int[L1[0].length];// 所有标号的点的下标集合,以标号的先后顺序进行存储,实际上是一个以数组表示的栈
//int[] zhb_router =new int[L1[0].length];
int count = 0;//被标号顶点的顺序或数目
int[] Distance = L1[start].clone();// v0到各点的最短距离的初始值
int index = start;// 从初始点开始
N[count] = index;// 把已经标号的下标存入下标集中
int []preIndex=new int[L1[0].length];//用于记录最短路径树中的节点的前一个节点序号
for (int i = 0; i < preIndex.length; i++) {//初始化为起始接点
preIndex[i]=start;
}
isLabel[index] = true;
while (true){
// 第一步:标号v_start,即w[start][0]行中找到距离v_start最近的点
int min = Integer.MAX_VALUE;
//找出与v_start距离最短的Distance的下标
for (int i = 0; i < Distance.length; i++) {
if (!isLabel[i] && Distance[i] != -1 && i != index) {
// 如果到这个点有边,并且没有被标号
if (Distance[i] < min) {
min = Distance[i];
index = i;// 记录下这个下标
}
}
}
isLabel[index] = true;//对点进行标号
count++;//增加一个标定的点
if (count>=Distance.length) {
break;//所有点已经遍历完
}
N[count] = index;// 把已经标号的下标存入下标集中
// 第二步:加入新的节点后,更新所有不在N中的节点的Distance
for (int i = 0; i < Distance.length; i++) {
//这个节点原来不可到达,刚加入的点和这个节点是互联的,并且不在N中
if (Distance[i] == -1 && L1[index][i] != -1&&!isLabel[i]) {//如果以前不可达,则现在可达了
Distance[i] = Distance[index] + L1[index][i];
preIndex[i]=index;//更新最短路径中当前接点的前一个接点
} else if (L1[index][i] != -1 && Distance[index] + L1[index][i] < Distance[i]) {
// 如果以前可达,但现在的路径比以前更短,则更换成更短的路径
//即先从
Distance[i] = Distance[index] + L1[index][i];
preIndex[i]=index;//更新最短路径中当前接点的前一个接点
}
}//每个节点到起始节点的最小距离更新完毕
}
//如果全部点都遍历完,则Distance中存储的是开始点到各个点的最短路径
for (int i = 0; i < Distance.length; i++) {
System.out.println("节点v"+start+"到节点v"+i+"的短距离为:"+(Distance[i]-Distance[start])+" 最短路径如下:");
outPutMinPath(preIndex, start, i, Distance.length);//输出最短路径
}
}
/*
*@author: ZhengHaibo
*web:     blog.csdn.net/nuptboyzhb
*mail:    zhb931706659@126.com
*2012-12-4  Nanjing njupt
*/
public static void main(String[] args) {
// 建立一个权值矩阵
int[][] L1 = { //测试数据1 无向图 实对称矩阵
{ 0,2,-1,1,-1,-1},
{ 2,0,3,2,-1,-1},
{ -1,3,0,3,1,5 },
{ 1,2,3,0,1,-1},
{-1,-1,1,1,0,2},
{-1,-1,5,-1,2,0}};
int[][] L2 =  { //测试数据2 有向图 非对称矩阵
{ 0,10,-1,30,100 },
{ -1,0,50,-1,-1 },
{ -1,-1,0,-1,10},
{-1,-1,20,0,60,},
{-1,-1,-1,-1,0}};
dijkstra(L1,0,5);
dijkstra(L2,0,4);
dijkstra(L1,0);
dijkstra(L2, 0);
/*//郑海波 2012年
* 运行结果 节点v0到节点v5的短距离为:4
* V0->V3->V4->V5
* 节点v0到节点v4的短距离为:60
* V0->V3->V2->V4
* 节点v0到节点v0的短距离为:0 最短路径如下:
*  V0->V0
*  节点v0到节点v1的短距离为:2 最短路径如下:
*  V0->V1
* 节点v0到节点v2的短距离为:3 最短路径如下:
*  V0->V3->V4->V2
*  节点v0到节点v3的短距离为:1  最短路径如下:
* V0->V3
* 节点v0到节点v4的短距离为:2 最短路径如下:
*  V0->V3->V4
*  节点v0到节点v5的短距离为:4 最短路径如下:
* V0->V3->V4->V5
* 节点v0到节点v0的短距离为:0 最短路径如下:
*  V0->V0
*  节点v0到节点v1的短距离为:10最短路径如下:
*   V0->V1
*   节点v0到节点v2的短距离为:50 最短路径如下:
*    V0->V3->V2
*    节点v0到节点v3的短距离为:30最短路径如下:
*    V0->V3
*    节点v0到节点v4的短距离为:60 最短路径如下:
*     V0->V3->V2->V4
*/
}
}


C++ STL版本

/*
*@author: ZhengHaibo
*web:     blog.csdn.net/nuptboyzhb
*mail:    zhb931706659@126.com
*2012-12-4  Nanjing njupt
*/
#include <iostream>
#include<vector>
#define MAXVALUE 65535
using namespace std;
void OutputMinPath(vector<int> prevIndex,int startIndex,int endIndex)
{
vector<int> path;
int i=endIndex;
path.push_back(i);
while(prevIndex[i]!=startIndex)
{
int k=prevIndex[i];
i=k;
path.push_back(i);
}
path.push_back(startIndex);
cout<<"---------------------"<<endl;
cout<<"路径顺序如下:"<<endl;
vector<int>::reverse_iterator rit;
for (rit=path.rbegin();rit<path.rend()-1;rit++)
{
cout<<"v"<<*rit<<"->";
}
cout<<"v"<<*rit<<endl;
}
void Dijkstra(vector< vector<int> > Lmatrix,int startIndex,int endIndex)
{
vector<int> Distance=Lmatrix[0];
vector<bool> isLabel(Distance.size(),false);
vector<int> N;
int count=0;
int index = startIndex;
N.push_back(index);
isLabel[index]=true;
vector<int> prevIndex(Distance.size(),startIndex);
while (count<Distance.size())
{
int min=MAXVALUE;
for(int i=0;i<Distance.size();i++)
{
if (!isLabel[i]&&Distance[i]!=-1&&i!=index)
{
if (Distance[i]<min)
{
min=Distance[i];
index=i;
}
}

}
if (index==endIndex)
{
break;
}
isLabel[index]=true;
count++;
N.push_back(index);
for (int j = 0;j<Distance.size();j++)
{
if (Distance[j]==-1&&Lmatrix[index][j]!=-1&&!isLabel[j])
{
Distance[j]=Distance[index]+Lmatrix[index][j];
prevIndex[j]=index;
}
else if (Lmatrix[index][j]!=-1&&Distance[index]+Lmatrix[index][j]<Distance[j])
{
Distance[j]=Distance[index]+Lmatrix[index][j];
prevIndex[j]=index;
}
}
}
cout<<"V"<<startIndex<<"到V"<<endIndex<<"的最短距离为:"<<Distance[endIndex]-Distance[startIndex]<<endl;
OutputMinPath(prevIndex,startIndex,endIndex);
}
void Dijkstra(vector< vector<int> > Lmatrix,int startIndex)
{
vector<int> Distance=Lmatrix[0];
vector<bool> isLabel(Distance.size(),false);
vector<int> N;
int count=0;
int index = startIndex;
N.push_back(index);
isLabel[index]=true;
vector<int> prevIndex(Distance.size(),startIndex);
while (true)
{
int min=MAXVALUE;
for(int i=0;i<Distance.size();i++)
{
if (!isLabel[i]&&Distance[i]!=-1&&i!=index)
{
if (Distance[i]<min)
{
min=Distance[i];
index=i;
}
}

}
isLabel[index]=true;
count++;
if (count>=Distance.size())
{
break;
}
N.push_back(index);
for (int j = 0;j<Distance.size();j++)
{
if (Distance[j]==-1&&Lmatrix[index][j]!=-1&&!isLabel[j])
{
Distance[j]=Distance[index]+Lmatrix[index][j];
prevIndex[j]=index;
}
else if (Lmatrix[index][j]!=-1&&Distance[index]+Lmatrix[index][j]<Distance[j])
{
Distance[j]=Distance[index]+Lmatrix[index][j];
prevIndex[j]=index;
}
}
}
for (int i = 0; i < Distance.size(); i++)
{
cout<<"节点v"<<startIndex<<"到节点v"<<i<<"的短距离为:"<<(Distance[i]-Distance[startIndex])<<" 最短路径如下:"<<endl;
OutputMinPath(prevIndex, startIndex, i);//输出最短路径
}
}
/*
*@author: ZhengHaibo
*web:     blog.csdn.net/nuptboyzhb
*mail:    zhb931706659@126.com
*2012-12-4  Nanjing njupt
*/
int main()
{
//测试数据1 无向图 实对称矩阵
int const N1=6;
int L1[N1][N1] = { \
{ 0,2,-1,1,-1,-1},
{ 2,0,3,2,-1,-1},
{ -1,3,0,3,1,5 },
{ 1,2,3,0,1,-1},
{-1,-1,1,1,0,2},
{-1,-1,5,-1,2,0}};
//测试数据2 有向图 非对称矩阵
int const N2=5;
int L2[N2][N2] =  { \
{ 0,10,-1,30,100 },
{ -1,0,50,-1,-1 },
{ -1,-1,0,-1,10},
{-1,-1,20,0,60,},
{-1,-1,-1,-1,0}};
vector< vector<int> > Lmatrix;
vector<int>  temp;
int i,j;
for (i=0;i<N1;i++)//将L1初始化到Lmatrix
{
for (j=0;j<N1;j++)
{
temp.push_back(L1[i][j]);
}
Lmatrix.push_back(temp);
temp.clear();
}
Dijkstra(Lmatrix,0,5);
Dijkstra(Lmatrix,0);
//////////////////////////////////////////////////////////////////////////
for (i=0;i<N2;i++)//将L1初始化到Lmatrix
{
for (j=0;j<N2;j++)
{
temp.push_back(L2[i][j]);
}
Lmatrix.push_back(temp);
temp.clear();
}
Dijkstra(Lmatrix,0,4);
Dijkstra(Lmatrix,0);
Lmatrix.clear();
//////////////////////////////////////////////////////////////////////////
return 1;
}
/*
V0到V5的最短距离为:4
---------------------
路径顺序如下:
v0->v3->v4->v5
节点v0到节点v0的短距离为:0 最短路径如下:
---------------------
路径顺序如下:
v0->v0
节点v0到节点v1的短距离为:2 最短路径如下:
---------------------
路径顺序如下:
v0->v1
节点v0到节点v2的短距离为:3 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4->v2
节点v0到节点v3的短距离为:1 最短路径如下:
---------------------
路径顺序如下:
v0->v3
节点v0到节点v4的短距离为:2 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4
节点v0到节点v5的短距离为:4 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4->v5
V0到V4的最短距离为:2
---------------------
路径顺序如下:
v0->v3->v4
节点v0到节点v0的短距离为:0 最短路径如下:
---------------------
路径顺序如下:
v0->v0
节点v0到节点v1的短距离为:2 最短路径如下:
---------------------
路径顺序如下:
v0->v1
节点v0到节点v2的短距离为:3 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4->v2
节点v0到节点v3的短距离为:1 最短路径如下:
---------------------
路径顺序如下:
v0->v3
节点v0到节点v4的短距离为:2 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4
节点v0到节点v5的短距离为:4 最短路径如下:
---------------------
路径顺序如下:
v0->v3->v4->v5
Press any key to continue
*/


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