基本思想
迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。
初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时更新数组dist(算导中称作Relax)。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。
伪代码
Dijkstra(G,w,s)
1. Initializ_single_source(G,s) //dist[] = INF, dist[s] = 0
2. S = 空集
3. Q=G.V
4. while Q != 空集
u = Extract-Min(Q)
S = SU{u}
for each vertex v属于G.adj[u]
Relax(u,v,w)
C++实现
#include<iostream>
#include<vector>
#include<stack>
//#include<limits.h>
using namespace std;
struct edge{
int noEnd; //边的终点序号
int w;
edge(int _no, int _w):noEnd(_no),w(_w){}
};
class Graph{
private:
vector<vector<edge>> Edge; //邻接表
vector<int> dist;
vector<char> vertex; // 顶点信息
int n; // 顶点个数
int e; //边数
vector<int> path; //记录着从源点v0到当前点最短路径的前驱节点序号
public:
Graph(int _n, int _e):n(_n),e(_e){
vertex.resize(n+1); //计数序号从1开始
Edge.resize(n+1);
path.resize(n+1);
dist.resize(n+1);
//初始化
for(int i=1; i<=n; i++){
path[i] = -1;
dist[i] = INT_MAX;
}
}
//依次读入顶点信息
void readVertex(){
cout<<"请依次输入顶点信息:"<<endl;
for(int i=1; i<=n; i++) cin>>vertex[i];
}
//依次读入边信息
void readEdge(){
cout<<"请依次输入边信息source,dst,weight:"<<endl;
int r,d,w; //r、d、w分别表示起点、终点、权重
for(int i=1; i<=e; i++){
cin>>r>>d>>w;
Edge[r].push_back(edge(d,w));
// Edge[d].push_back(edge(r,w)) 无向图
}
}
void Dijkstra(int v0);
// v0是源点
void printPath(int v, int v0){
stack<int> s;
while(v != v0){
s.push(v);
v = path[v];
}
cout<<endl<<vertex[v0];
while(!s.empty()){
v = s.top();
s.pop();
cout<<"->"<<vertex[v];
}
cout<<endl;
}
};
void Graph::Dijkstra(int v0){
dist[v0] = 0;
vector<bool> isVisited(n+1,false);
isVisited[v0] = true;
for(int i=0; i<Edge[v0].size(); i++){
edge tmp = Edge[v0][i];
if(dist[v0] + tmp.w < dist[tmp.noEnd]){
dist[tmp.noEnd] = dist[v0] + tmp.w;
path[tmp.noEnd] = v0;
}
}
int N=n-1;
while(N--){
//找到下一个加入S集合中的点
int u = -1;
int tmpMin = INT_MAX;
for(int i=1; i<=n; i++){
if(!isVisited[i] && dist[i] < tmpMin){
u = i;
tmpMin = dist[i];
}
}
isVisited[u] = true;
//Relax 更新dist
for(int i=0; i<Edge[u].size(); i++){
edge tmp = Edge[u][i];
if(dist[u] + tmp.w < dist[tmp.noEnd]){
dist[tmp.noEnd] = dist[v0] + tmp.w;
path[tmp.noEnd] = u;
}
}
}
}
int main(){
int n,e;
cout<<"请输入顶点数,边数:"<<endl;
cin>>n>>e;
Graph graph(n,e);
graph.readVertex();
graph.readEdge();
int v0, v;
cout<<"请输入源点及终点序号:"<<endl;
cin>>v0>>v;
graph.Dijkstra(v0);
graph.printPath(v,v0);
cout<<endl;
}