介绍
迪杰斯特拉算法,是求从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
大体思路
-
初始化:设置一个集合
S
,用于存储已经找到最短路径的顶点。初始时,S
只包含源点。同时,创建一个数组dist[]
来存储从源点到每个顶点的最短路径权重,初始时除了源点的dist
值为0,其他所有顶点的dist
值设为无穷大(表示尚未找到路径)。 -
选择最小距离顶点:从未加入
S
的顶点集合中,选择一个dist[]
值最小的顶点u
,作为当前顶点。 -
松弛操作:对当前顶点
u
的所有邻接顶点v
,进行松弛操作。如果通过顶点u
到达邻接顶点v
的路径权重小于当前记录的dist[v]
,则更新dist[v]
为新的更小的权重,并且更新path[v]
为当前顶点u
。 -
更新集合S:将当前顶点
u
加入到集合S
中,表示已经找到了从源点到顶点u
的最短路径。 -
重复过程:重复步骤2和3,直到所有顶点都被加入到集合
S
中,或者当选择出的最小dist[]
值不再改变时(表示没有更短的路径可以找到)。 -
路径回溯:如果需要输出从源点到某个特定顶点的最短路径,可以通过
path[]
数组回溯来构建路径。
实现步骤
头文件
1.0结构体定义
2.0 辅助容器
其中visited容器是为了判断点是否已经经过过。
dist数组则记录了,初始顶点到目标顶点的距离。(是初始顶点,比如路径0-2-3,那么dist[3]是从0到2到3的路径距离) 。
path数组则记录了当前顶点的父顶点。我们就是通过父节点来抽象的将顶点加入路径的。最后还可以通过父顶点一路回溯,输出路径。
3.0迪杰斯特拉算法
整体框架类似于普里姆算法(Prim算法,这一章中有对内外循环以及u=-1的解释)。贪心算法的思想,依次优先将小值点“访问”(visit),再更新与相邻顶点dist的值。
4.0初始化,添加边以及输出操作
打印输出操作中,利用的栈先进后出的特点,依次逆序将路径中的顶点压入栈中,最后依次弹出,输出顺序即为路径的顺序。
本片内容旨在提供迪杰斯特拉的算法c++实现,至于代码中没有对指针进行后续管理比如delete操作,不作赘述。
最后提醒一句,在当前代码中,Dijkstra(v)表示,以v为起始点,构建最短路径;print(u)表示从起始点到u点的路径及权重。
源代码
#include<iostream>
#include<vector>
#include<climits>
class ALGraph{
private:
struct Edge{
int target;//顶点索引
int weight;//权重
Edge*next;//
};
public:
int V;//顶点数量
std::vector<Edge*>adj;
std::vector<bool>visited;
std::vector<int>dist;
std::vector<int>path;
//初始化
ALGraph(int V):V(V),adj(V,nullptr),visited(V,false),dist(V,INT_MAX),path(V,-1){}
//添加边
void AddEdge(int a,int b,int weight = 0){
Edge*edge = new Edge{b,weight,adj[a]};
adj[a] = edge;
}
//迪杰斯特拉
void Dijkstra(int v){
dist[v] = 0;
for(int i =0;i<V;i++){
int u = -1;
for(int k = 0;k<V;k++){
if(!visited[k]&&(u==-1||dist[k]<dist[u])){
u = k;
}
}
visited[u] = true;
for(Edge*p = adj[u];p!=nullptr;p = p->next){
int target = p->target;
if(!visited[target]&&(dist[target]>dist[u]+p->weight)){
path[target] = u;
dist[target] = dist[u]+p->weight;
}
}
}
}
//打印输出
void print(int t){
std::vector<int>pathstack;
int current = t;
while(path[current]!=-1){
pathstack.push_back(current);
current = path[current];
}
pathstack.push_back(current);
while (!pathstack.empty()) {
std::cout << pathstack.back();
if (pathstack.size() > 1) std::cout << "-->";
pathstack.pop_back();
}
std::cout << "=="<< dist[t] << std::endl; // 打印总权重
}
};
int main()
{
ALGraph g(5);
g.AddEdge(0,1,10);
g.AddEdge(0,3,7);
g.AddEdge(0,4,5);
g.AddEdge(1,2,6);
g.AddEdge(1,4,2);
g.AddEdge(2,3,6);
g.AddEdge(2,4,9);
g.AddEdge(3,4,2);
g.Dijkstra(0);
g.print(2);
return 0;
}
举例验证,结果正确。