目录
1.介绍
(1)适用范围
Dijkstra仅适用于求解所有权值均为非负数的图的最短路径问题
(2)算法思想——贪心
初始化条件:
对图G=(V, E)、邻接矩阵为matrix[|V|][|V|]、源点为src,设:
- 集合S,已知最短路径的终点集
- 一维数组dist[|V|],dist[i]表示src~i的目前最短路径的长度
贪心算法:
- 贪心选择:选出dist中最小的元素dist[j](j∈V-S),则dist[j]就是src~j的最短路径,然后将顶点j加入S
- 最优子结构:对任意k∈V-S,src~k的目前最短路径要么是dist[k],要么是dist[j]+matrix[j][k],即dist[k]=min(dist[k], dist[j]+matrix[j][k])
伪代码如下:
S={src};
for(auto i:V){
dist[i]=matrix[src][i];
}
while(S!=V){
选出dist中最小的元素dist[j],j∈V-S;
S+={j};
for(auto k:V-S){
if(matrix[j][k] != 无穷大){
dist[k]=min(dist[k], dist[j]+matrix[j][k]);
}
}
}
2.算法实现
(1)数据结构
#include <iostream>
#include <vector>
#include <string>
#include <limits> // std::numeric_limits<int>::max()
#include <algorithm> // std::min()
class Dijkstra{
private:
std::vector<std::vector<int>> matrix; // 邻接矩阵
std::vector<bool> visit; // visit[i]=true表示顶点i∈S
std::vector<int> dist; // dist[i]表示源点到顶点i的目前最短路径的长度
std::vector<std::string> path; // path[i]表示源点到顶点i的最短路径
int MAX; // 无穷大
private:
void init(int n, const std::vector<std::vector<int>> &edge);
public:
std::vector<std::string> shortestPath(int n, const std::vector<std::vector<int>> &edge, int src);
};
(2)初始化
void Dijkstra::init(int n, const std::vector<std::vector<int>> &edge, int src){
MAX=std::numeric_limits<int>::max();
matrix=std::vector<std::vector<int>>(n,std::vector<int>(n, MAX));
visit=std::vector<bool>(n);
dist=std::vector<int>(n, MAX);
path=std::vector<std::string>(n);
visit[src]=true;
for(auto vec:edge){
matrix[vec[0]][vec[1]]=vec[2];
if(vec[0] == src){
dist[vec[1]]=vec[2];
}
}
}
(3)单源最短路径
最终dist保存单源最短路径的长度,path保存单源最短路径:
std::vector<std::string> Dijkstra::shortestPath(int n, const std::vector<std::vector<int>> &edge, int src){
init(n, edge, src);
int count=1;
int i,j,k;
// S != V
while(count < n){
// 尝试寻找最小元素dist[j],j∈V-S
auto mincost=MAX;
for(i=0,j=-1; i<n; i++){
if(!visit[i] && dist[i]<mincost){
j=i;
mincost=dist[i];
}
}
if(j != -1){
// 找到最小元素dist[j],j∈V-S
// 将j加入S、更新dist[k],k∈V-S
visit[j]=true;
count++;
path[j]=path[j]+"-->"+std::to_string(j);
for(k=0; k<n; k++){
if(!visit[k] && matrix[j][k]!=MAX && dist[j]+matrix[j][k]<dist[k]){
dist[k]=dist[j]+matrix[j][k];
}
}
}else{
// 没找到最小元素dist[j],j∈V-S
// 说明V-S中剩余的顶点均不可达,可提前结束循环
break;
}
}
// 给最短路径加上源点
for(i=0; i<n; i++){
if(visit[i] && i!=src){
path[i]=std::to_string(src)+path[i];
}
}
return path;
}
(4)性能分析
时间性能:
最多进行|V|-1躺贪心选择,每次选择最小元素dist[j](j∈V-S)需要遍历整个dist,时间复杂度为O(|V|)。每次将选择的顶点加入S后,又要遍历整个dist以修改dist[k](k∈V-S),时间复杂度为O(|V|)。给最短路径path加源点的操作由问题的需求决定,遍历整个path需要O(|V|)。
空间性能:
若不考虑邻接矩阵matrix与最短路径path的存储空间,则还需额外的dist[|V|]和visit[|V|],空间复杂度为O(|V|)。
整体性能:
- T(n)=O(|V|^2)
- S(n)=O(|V|)