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;
}