数据结构——图
一、Dijkstra算法
1. 算法过程
首先定义一个辅助集合
S
S
S,
S
S
S中包括了已经加入到最短路径中的顶点,例如使用一个数组来实现s[]
,s[i] = 1
代表第
i
i
i个顶点加入到了最短路径。然后定义两个辅助数组:
dist[]
:记录了从源点 v 0 v_0 v0开始,到剩余顶点的最短路径长度,初值为dist[i] = arcs[0][i]
path[]
:path[i]
记录了从源点 v 0 v_0 v0到顶点 v i v_i vi的最短路径的前驱结点,再每次算法结束时,可以回溯 v 0 v_0 v0到 v i v_i vi的最短路径。
算法过程:
- 初始化:集合
S
S
S初始化为{0},初始化
dist[]
- 从顶点集合 V − S V-S V−S中选出 v j v_j vj,满足 d i s t [ j ] = M i n { d i s t [ i ] ∣ v i ∈ V − S } dist[j] = Min\{dist[i] | v_i \in V-S\} dist[j]=Min{dist[i]∣vi∈V−S},这里就得到了一条从 v 0 v_0 v0到 v j v_j vj的最短路径。 S = S ∪ j S=S \cup {j} S=S∪j
- 修改从
v
0
v_0
v0出发到
V
−
S
V-S
V−S任意一点
v
k
v_k
vk的最短路径长度:
if (dist[j] + arcs[j][k] < dist[k]) dist[k] = dist[j] + arcs[j][k];
- 重复上述步骤,直到所有的顶点都在 S S S中。
2. 代码
template <typename T>
void Graph<T>::_dijkstra(int v, int *path, int *shortpath) const {
bool *visited = new bool [vexnum];
for (int i = 0; i < vexnum; ++i)
visited[i] = false;
visited[v] = true;
path[v] = -1;
shortpath[v] = 0;
int k = v;
int nextk = -1;
EdgeNode *p;
int count = 0;
for (int i = 1; i < vexnum; ++i) {
for (p = vexlist[k].first; p; p = p->next) {
int j = p->adjvex;
if (!visited[j] && shortpath[j] > shortpath[k] + p->weight)
shortpath[j] = shortpath[k] + p->weight;
}
nextk = _findMinLen(shortpath, visited); // 查找源点邻点中权值最小的
if (nextk == -1)
break;
else {
visited[nextk] = true; // 将找到的点加入到最短路径中
path[nextk] = k;
k = nextk;
count++;
}
}
std::cout << "shortest path: " << std::endl;
int lastVer;
std::stack<int> tmp;
for (int i = 1; i <= count; ++i) {
std::cout << shortpath[k] << " : ";
tmp.push(k);
lastVer = path[k];
while (lastVer != v) {
tmp.push(lastVer);
lastVer = path[lastVer];
}
tmp.push(v);
std::cout << tmp.top();
tmp.pop();
while (!tmp.empty()) {
std::cout << "->" << tmp.top();
tmp.pop();
}
std::cout << "\n";
k = path[k];
}
}