顶点间最短路径长度之探寻算法
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; } } } }