Dijkstra算法实现单源最短路径

参考《计算机算法设计与分析(第二版)》王晓东电子工业出版社

 大二时地理信息系统实习写过Dijkstra寻找最短路径程序,当时对计算机编程还不熟悉,很多知识都不了解,尤其是算法等,今天重新编了一遍,也较为清楚了。以下是自己零星所想,一些思维片段,或许不容易理解。编程以蔽之。

Dijkstra算法思想:

顶点集合G=(V,E)

已知w[i][j]为边(i,j)的权。当(ij)∉E时,w[i][j]=INT_MAX最大数,视为无边路径连接

dist[i]表示当前从源到顶点i的最短特殊路径长度。


带权有向图G=(V,E)V={1,2,。。。},顶点int start是源

输入为

int n点个数

int start

w[i][j]为边(i,j)的权。当(ij)∉E时,w[i][j]=INT_MAX最大数,视为无边路径连接

输出:

Type dist[i]表示当前从源到顶点i的最短特殊路径长度。

int prev[i]表示从starti点的最短路径中,i点的前一个点。初始第一步:

集合S(贪心集)初始没有元素。

bool s[n] ;

for all s[i];

s[i]=false;s中没有任何元素

for(int i=1;i<=n;i++)

{

     dist[i]=w[start][i];//起点到第i点的距离

     if(dist[i]==INT_MAX)//起点到i点无边连接

         prev[i]=0;//starti点的最短路径中,i点的前一个点为0,也就是没有边连接

     else prev[i]=start;// starti点直接相连,也就是说从starti点的最短路径中,i点的前一个点为start

}

初始化求得start点到各点的直接距离。

dist[start]=0; //start到自身距离为0

s[start]=true;//此时已经求得经过start点到各点的最短距离,所以将源start加到贪心集s中。

//剩余n-1个点,求经过u点到其余各点的最短距离,直至所有点多加入到s中,此时结束

for(int i=1;i<n;i++)//i次循环,每次循环加入特殊最短路径

{

     int temp=INT_MAX

     int u=start;//

     for(int j=1;j<=n;j++)

     {

        if((!s[j]) && (dist[j] <temp))

         {

              u=j;//对每一个点,查看是否在s中,如果还未加入s,并且小于temp

              temp = dist[j];

         }

     }//得到联通startjjV-S)最短特殊路径的u点(uV-S

     //u加入s

     s[u]=true;

     for(int j=1;j<=n;j++)

     {

        if((!s[j]) && (w[u][j] <INT_MAX))

             {

                     Type newdist=dist[u]+w[u][j];

             if(newdist < dist[j])

              {

                               dist[j]=newdist;

                                   prev[j]=u;

                            }

                     }

              }

}

也就是说先假设源start点到各点的连接距离为最短距离,然后判断新加入一个点u,如果通过u点能使连接各点的距离缩短,就将start点到i点的距离更新,且记i点的前一节点为u。把u点加入到s集合中,也就是说,经过s中的点到各点的最短距离和相应路径已经知道,从剩余的V-S中取出联通距离最短的一点u加入到结合S,并判断u是否能使目前startV-S中最短距离缩短,如果能则修改最短距离dist[i]V-S各点的前一节点为u。直至所有节点都加入到Sdist就记录了从源到所有其他顶点之间的最短路径长度。

 

VC++下编程实现

// Dijkstra.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "vector"
const double INFINITE=99999999;
/************************************************************************************************/
/* 输入为 Dijkstral单源最短路径
*	int		n			点个数
*	int		start		源
*	weight[i][j]		边(i,j)的权。当(i,j)不属于E时,w[i][j]=INFINITE最大数,视为无联通
*
* 输出:
*	Type dist[i]	表示当前从源到顶点i的最短特殊路径长度。
*	int  prev[i]	表示从start到i点的最短路径中,i点的前一个点。
* 作者:Archie
* 日期:2012年9.2日
*************************************************************************************************/
void Dijkstral(int n,int start,double *w,double dist[],int prev[]);
double weight[]={0.0		,10.0		, INFINITE	, 30		,100		,
				INFINITE	,0			, 50		, INFINITE	,INFINITE	,
				INFINITE	,INFINITE	, 0			, INFINITE	,10			,
				INFINITE	,INFINITE	, 20		, 0			,60			,
				INFINITE	,INFINITE	, INFINITE	, INFINITE	,0		};
int main(int argc, char* argv[])
{
	int n=5;
	int start=1;
	double dist[5];
	int prev[5];
	Dijkstral(n, start, weight, dist, prev);
	for (int i=0;i<n; i++)
	{
		std::vector<int> path;
		path.push_back(i);
		int t=prev[i];
		while (t!=-1 && t!=start-1)
		{
			path.push_back(t);
			t=prev[t];
		}
		path.push_back(start-1);
		printf("第%d个点到第%d个点的最短距离为%f\n",start,i+1,dist[i]);
		printf("其路径为:\n");
		for (std::vector<int>::reverse_iterator r_iter=path.rbegin();r_iter!=(path.rend()-1);r_iter++)
			printf("%d—>",(int)*r_iter+1);
		printf("%d\n",i+1);
	}

	return 0;
}
void Dijkstral(int n,int start,double *w,double dist[],int prev[])
{
	
	bool *s=new bool[n];
	for(int i=1;i<=n;i++)
	{
		s[i-1]=false;				//初始集合S(贪心集)没有元素
		dist[i-1]=*(w+(start-1)*n+(i-1));	//起点start到第i点的距离 传进来的数组须连续存放即数组形式a[m][n]
		if(dist[i-1]==INFINITE)		//起点到i点无边连接
			prev[i-1]=-1;			//从start到i点的最短路径中,i点的前一个点为-1,也就是没有边连接
		else prev[i-1]=start-1;		//start和i点直接相连,也就是说从start到i点的最短路径中,i点的前一个点为start
	}
	//	初始化求得start点到各点的直接距离。
	dist[start-1]=0;				//start到自身距离为0
	s[start-1]=true;				//此时已经求得经过start点到各点的最短距离,所以将源start加到贪心集s中。

	//剩余n-1个点,循环第i个点u加入s,直至所有点加入到s中
	for(i=0;i<n-1;i++)
	{
		double temp=INFINITE;
		int u=start-1;//源
		for(int j=0;j<n;j++)
		{
			if((!s[j]) && (dist[j] <temp))
			{
				u=j;//对每一个点,查看是否在s中,如果还未加入s,并且小于temp
				temp = dist[j];
			}
		}//得到联通start到j(j∈V-S)最短特殊路径的u点(u∈V-S)
		//将u加入s
		s[u]=true;
		for(j=0;j<n;j++)
		{
			if((!s[j]) && (*(w+u*n+j) <INFINITE))
			{
				double newdist=dist[u]+*(w+u*n+j);
				if(newdist < dist[j])
				{
					dist[j]=newdist;
					prev[j]=u;
				}
			}
		}
	}
	if (s!=NULL)
	{
		delete[]s;
		s=NULL;
	}
	
}


针对上图结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值