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

源码下载: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
*/


  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Dijkstra算法是一种用于求解单源最短路径的经典算法。它以一个源顶点为起始点,通过不断扩展最短路径树来寻找到其他所有顶点的最短路径。下面是Dijkstra算法的思路和步骤。 首先,我们需要定义一个顶点集合,用于存放已经求得最短路径的顶点。算法开始时,所有顶点都被标记为未被访问,并且它们的最短路径长度都初始化为无穷大。 然后,我们从起始顶点开始,将其最短路径长度置为0,并将其加入到已求得最短路径的集合中。此外,我们还需要更新起始顶点的邻居顶点的最短路径长度。 接下来,我们进入循环,不断选择最短路径长度最小的顶点,将其加入到已求得最短路径的集合中。然后,更新该顶点的邻居顶点的最短路径长度。具体的更新方式是,如果通过当前选中的顶点访问邻居顶点的路径长度比已知的最短路径长度小,那么更新邻居顶点的最短路径长度。 最后,当所有顶点都被加入到已求得最短路径的集合中,或者存在无穷大的路径时,算法结束。此时,我们得到了从起始顶点到其他所有顶点的最短路径长度。 Dijkstra算法的时间复杂度为O(V^2),其中V为中顶点的数量。此外,它还可以通过使用优先队列来优化,将时间复杂度降低到O((V+E)logV),其中E为中边的数量。 总之,Dijkstra算法是一种求解单源最短路径的有效算法,它可以应用于各种实际问题中,如路由选择、网络通信、物流规划等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值