我们在用没有优化过的版本的时候,里面有一段代码:
int u = -1, MIN = INF;
for (int j = 0; j < n; j++)
{
if (vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
这个代码的作用在于寻找所有当前结点能到的结点中距离最短的,也就是这一步,我们可以用优先队列来实现优化
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
struct node {
int x, d;//x是标号,d是边权(就是起点到这个点的距离)
node() {}
node(int a, int b) { x = a; d = b; }
bool operator < (const node & a) const//因为STL库函数优先队列的需要,必须重载运算符,规定优先级顺序
{
if (d == a.d) return x<a.x;
else return d > a.d;
}
};
const int MAXN = 1000;
const int INF = 10000000;
vector<node> Adj[MAXN];//Adj[u]存放从顶点u可以走到的所有结点
int n, m, s;//顶点个数,边数,起点编号
int dis[MAXN];//保存从起点到所有点的最短距离
void Dijkstra(int s)
{
fill(dis, dis + n, INF);
dis[s] = 0;
priority_queue<node> q;//定义一个优先队列
q.push(node(s, dis[s]));
while (!q.empty())
{
node x = q.top();//取出头节点,也就是距离起点最近的结点
q.pop();
for (int i = 0; i < Adj[x.x].size(); i++)//循环头节点能够到达的所有节点
{
node y = Adj[x.x][i];
if (dis[y.x] > x.d + y.d)//如果这个结点到起点的距离大于头节点到起点的距离加上头节点到这个结点的距离
{
dis[y.x] = x.d + y.d;//更新数据
q.push(node(y.x, dis[y.x]));
}
}
}
}
int main()
{
int u, v, w;
cin >> n >> m >> s;//顶点个数,边数,起点编号
for (int i = 0; i < m; i++)
{
cin >> u >> v >> w;//u和v是两个结点,表示从u走到v的距离是w
Adj[u].push_back(node(v,w));
}
Dijkstra(s);
for (int i = 0; i < n; i++)
{
cout << dis[i] << " ";
}
system("pause");
return 0;
}
这个优化后的代码与没有优化的代码之间还有一盒区别,就是没有了数组vis,这个数组在没有优化代码中表示的是当前结点有没有被访问过,但是在优化的代码中,因为每次取出头节点之后就会直接把这个结点pop掉,而且每次都是只有出现能够优化的路线才将结点纳入队列中,所以没有这个必要检测当前结点是否走过