算法简介
SPFA(Shortest Path Faster Algorithm)算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法。
很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了
算法的基本思路
我们用数组dis记录每个结点的最短路径估计值,用邻接表或邻接矩阵来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止
代码实现
bool Graph::SPFA(int begin) {
bool *visit;
//visit用于记录是否在队列中
visit = new bool[this->vexnum];
int *input_queue_time;
//input_queue_time用于记录某个顶点入队列的次数
//如果某个入队列的次数大于顶点数vexnum,那么说明这个图有环,
//没有最短路径,可以退出了
input_queue_time = new int[this->vexnum];
queue<int> s; //队列,用于记录最短路径被改变的点
/*
各种变量的初始化
*/
int i;
for (i = 0; i < this->vexnum; i++) {
visit[i] = false;
input_queue_time[i] = 0;
//路径开始都初始化为直接路径,长度都设置为无穷大
dis[i].path = this->node[begin-1].data + "-->" + this->node[i].data;
dis[i].weight = INT_MAX;
}
//首先是起点入队列,我们记住那个起点代表的是顶点编号,从1开始的
s.push(begin - 1);
visit[begin - 1] = true;
++input_queue_time[begin-1];
//
dis[begin - 1].path =this->node[begin - 1].data;
dis[begin - 1].weight = 0;
int temp;
int res;
ArcNode *temp_node;
//进入队列的循环
while (!s.empty()) {
//取出队首的元素,并且把队首元素出队列
temp = s.front(); s.pop();
//必须要保证第一个结点不为空
if (node[temp].firstarc)
{
temp_node = node[temp].firstarc;
while (temp_node) {
//如果边<temp,temp_node>的权重加上temp这个点的最短路径
//小于之前temp_node的最短路径的长度,则更新
//temp_node的最短路径的信息
if (dis[temp_node->adjvex].weight > (temp_node->weight + dis[temp].weight)) {
//更新dis数组的信息
dis[temp_node->adjvex].weight = temp_node->weight + dis[temp].weight;
dis[temp_node->adjvex].path = dis[temp].path + "-->" + node[temp_node->adjvex].data;
//如果还没在队列中,加入队列,修改对应的信息
if (!visit[temp_node->adjvex]) {
visit[temp_node->adjvex] = true;
++input_queue_time[temp_node->adjvex];
s.push(temp_node->adjvex);
if (input_queue_time[temp_node->adjvex] > this->vexnum) {
cout << "图中有环" << endl;
return false;
}
}
}
temp_node = temp_node->next;
}
}
}
//打印最短路径
return true;
}
转载于链接