Dijkstra算法
Dijkstra算法是求解有向图最短路径的经典算法,计算从一个指定的初始结点到其他各个结点最短路径。它的理论基础就是一条最短路径的子路径也一定是最短的。
实现如下:
- 将所有结点分为两个集合,一个命名为S集,一个命名为U集。S集中的点是我们已知其最短路径的点,U集中的点是我们还未知其最短路径的点。因此初始时刻,S集中只有一个我们选定的起始点,U集中是除了起始点意外的所有点;而最终时刻,S集中应该包含所有的点,U集为空集。
- 从最后加入S集的u点出发,选出到U集中最短的那个点nextVertex,将nextVertex点加入S集,并从U集中移除nextVertex点。
- 更新U集各点到起点的距离。如果从起点到u点再到U集中某点的距离比之前保存的距离小,就更新,否则不更新。
图例:用Dijkstra算法求解如下图的最短路径
感觉这是我看到的一个最好理解图。
附上实现代码:
#include<iostream>
#include<vector>
#include<stack>
using namespace std;
int map[][5] = { //邻接矩阵
{0,10,INT_MAX,INT_MAX,5},
{INT_MAX,0,1,INT_MAX,2},
{INT_MAX,INT_MAX,0,4,INT_MAX},
{7,INT_MAX,6,0,INT_MAX},
{INT_MAX,3,9,2,0}
};
void Dijkstra(
const int numOfVertex, //图中结点个数
const int startVertex, //起始结点编号
int map[][5], //距离邻接矩阵
int* distance, //起始结点到当前结点最短路径的距离
int* prevVertex //路径中,当前点的上一个结点编号
)
{
vector<bool> isIns; //当前点所属集合,true表示在S中,false表示在U中
isIns.reserve(0); //预分配空间
isIns.assign(numOfVertex, false); //赋false初值
for(int i=0;i<numOfVertex;++i) //初始化distance以及prevVertex
{
distance[i] = map[startVertex][i];//初始化distance
if(map[startVertex][i] < INT_MAX) //如果起点到当前点存在路径,则将当前点的上一点初始化为起始点
prevVertex[i] = startVertex;
else
prevVertex[i] = -1; //不存在时设置为-1
}
prevVertex[startVertex] = -1; //起始点的上一点为-1
int u = startVertex; //u为S集中最后加入的点,即从该点开始搜索
for(int i=1;i<numOfVertex;++i) { //从U集中搜索当前distance最小点
int nextVertex = u; //nextVertex为即将加入S集的点
int tempDistance = INT_MAX;
for (int j = 0; j < numOfVertex; ++j) {
if ((isIns[j] == false) && (distance[j] < tempDistance)) { //j不在S集且到j的距离比上一个点小
nextVertex = j; //设置j为即将加入S集的点
tempDistance = distance[j]; //这不用解释了,太明显了不知道说些什么了
}
}
isIns[nextVertex] = true; //U集中distance最小的点,加入S集
u = nextVertex; //u设置为S集中最后加入的点,接下来从这里开始继续找
for (int j = 0; j < numOfVertex; ++j) { //更新U集中的distance
if ((isIns[j] == false) && (map[u][j] < INT_MAX)) {//如果U集,且有路径到达
int temp = distance[u] + map[u][j]; //比较从起始点到u再到j距离与之前j的distance
if (temp < distance[j]) { //更小的时候就更新distance
distance[j] = temp;
prevVertex[j] = u;
}
}
}
}
}
int main(int argc,const char* argv[])
{
int distance[5];
int preVertex[5];
for(int i=0;i<5;++i)
{
Dijkstra(5,i,map,distance,preVertex);
for(int j=0;j<5;j++)
{
int index = j;
stack<int> trace;
while(preVertex[index]!=-1)
{
trace.push(preVertex[index]);
index = preVertex[index];
}
cout<<"路径:";
while(!trace.empty())
{
cout << trace.top() << "--";
trace.pop();
}
cout<<j;
cout<<" 距离是 "<<distance[j]<<endl;
}
}
return 0;
}