顶点间最短路径长度之探寻算法

1.最短路径概念

         在一个无权的图中,若从一顶点到另一顶点存在着一条路径,则称该路径长度为该路径上所经过的边的数目,它等于该路径上的顶点数减1。由于从一顶点到另一顶点可能存在着多条路径,每条路径上所经过的边数可能不同,即路径长度不同,我们把路径长度最短(即经过的边数最少)的那条路径叫做最短路径,其路径长度叫做最短路径长度或最短距离。
  
        对于带权的图,考虑路径上各边上的权值,则通常把一条路径上所经边的权值之和定义为该路径的路径长度或称带权路径长度。从源点到终点可能不止一条路径,把带权路径长度最短的那条路径称为最短路径,其路径长度(权值之和)称为最短路径长度或者最短距离。

2.Dijkstra狄克斯特拉算法

     思路

       创建标号表flag, index为节点编号,flag[index]表征节点是否已经访问。创建矩阵path,path[index]的值为,起点from到顶点index的最短路径中到顶点index的上一个节点,-1表示起点到当前节点无路径。创建矩阵dist,dist[index]的值为,起点form到顶点index的最短路径。

       设定起点为from。

       (1)初始化,除flag[from]之外的值均为false,代表尚未探寻成功最短路径。初始化dist的值为起点直接到当前节点的路径长度。初始化path的所有值为from,若起点到该顶点无路径,设定为-1。

       (2) 进行n-1次循环:

           a.寻找最短路径顶点:遍历寻找dist中,值最小且尚未探寻成功最小路径的顶点并记录其标号index。

           b.标记最短路径顶点:flag[index]为true.代表到该顶点的最小路径该已经探寻成功。

           c.更新剩余顶点的最短距离矩阵dist和路径矩阵path:遍历比较以index为中继点到剩余顶点的距离,和当前记录的最小距离dist。若前者小,则更新最小距离,并将path的对应值更新为中继点标号index。


     特点:

        (1).Dijkstra 算法中的两重循环都是关于n的,所以时间复杂度为:O(n.^2)。由于需要辅助标记矩阵flag,空间复杂度为O(n).

        (2).仅仅适用于正权值图


     代码

//狄克斯特拉算法求最短路径
// adjMatrix--邻接矩阵
// n--顶点总数
// from--起始节点数
//path[index]的值为,起点from到顶点index的最短路径中到顶点index的上一个节点,-1表示起点到当前节点无路径
//dist[index]的值为,起点form到顶点index的最短路径

void dijkstra(int** adjMatrix,int n,int from,int* path,int* dist){

	bool* flag=new bool[n];//顶点是否已经探寻

	//initialization
	for(int i=0;i<n;i++){
		dist[i]=adjMatrix[from][i];
		flag[i]=false;
		if(i!=from&&dist[i]<MAX)
	     	   path[i]=from;
		else
		   path[i]=-1;//代表无路径
	}
	dist[from]=0;
	flag[from]=true;

	int minDist,minIndex;
	for(int k=1;k<n;k++){//主循环,还有n-1个顶点需要探寻路径

	   //寻找dist当前最短路径并记录标号
	   minDist=MAX;
	   minIndex=-1;
	   for(int i=0;i<n;i++)
		if(!flag[i]&&dist[i]<minDist){
			  minDist=dist[i];
			  minIndex=i;
		}

           flag[minIndex]=true;//代表顶点minIndex的最短路径已经探寻成功

	   //以顶点minIndex为中继点,探寻到其余为探寻顶点的最短路径并更新dist和path
	   for(int i=0;i<n;i++)
		   if(!flag[i]&&(minDist+adjMatrix[minIndex][i])<dist[i]){
			  dist[i]=minDist+adjMatrix[minIndex][i];
			  path[i]=minIndex;
	   }
     }
}


3.Floyd弗洛伊德算法和顶点间的最短路径

     思路

               (1)初始化距离矩阵dist和路径矩阵path

               (2)循环0:k,对于每一个路径点[i][j](排除对角线点,自己以自己为中继的点)

                   a.dist[i][j]=min{ dist[i][j], dist[i][k]+dist[k][j]},即每次保证当添加k为中继点时,取路径最短的。

                   b.若更新成功,则path[i][j]=path[i][k]。path[i][j]中的值为i到j的最短路径中,i之后顶点的序号。由于此时k为中继点,则可以把路径分为2段,且path[i][j]=path[i][k]无疑问。

     分析

                时间复杂度为O(n.^3),空间复杂度为O(n.^2)

     代码

//floyd算法求点之间的最短路径
void floyd(int adjMatrix[4][4],int path[4][4],int dist[4][4]){
	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++){
			path[i][j]=j;//初始化,表示i到j的路径的下一顶点
			dist[i][j]=adjMatrix[i][j];//初始化
		}
        for(int k=0;k<4;k++){
	  for(int i=0;i<4;i++)
		for(int j=0;j<4;j++){
			if(i==k||j==k||i==j) continue;
			if(dist[i][j]>dist[i][k]+dist[k][j]){
				dist[i][j]=dist[i][k]+dist[k][j];//更新最短距离
				path[i][j]=path[i][k];//更新路径
			}
		} 
   }
}
void main(){
	int adjMatrix[4][4]={{0,1,100,4},{100,0,9,2},{3,5,0,8},{100,100,6,0}};

	int path[4][4],dist[4][4];
	floyd(adjMatrix,path,dist);

	for(int i=0;i<4;i++)
		for(int j=0;j<4;j++){
			if(i!=j){
			  cout<<i<<"->"<<j<<":  ";
			  if(dist[i][j]>=100)
				  cout<<"不存在路径"<<endl;
			  else{
				  cout<<"dist: "<<dist[i][j]<<",path: ";
				  int pre=i;
				  while(pre!=j){
					  cout<<pre<<"--";
					  pre=path[pre][j];
				  }
				  cout<<j<<endl;
			  }
		}
	}
}





原文地址:https://www.cnblogs.com/engineerLF/p/5393033.html