Dijkstra算法學習

Dijkstra算法

Dijkstra算法是求解有向圖最短路徑的經典算法,計算從一個指定的初始結點到其他各個結點最短路徑。它的理論基礎就是一條最短路徑的子路徑也一定是最短的。

實現如下:

  1. 將所有結點分爲兩個集合,一個命名爲S集,一個命名爲U集。S集中的點是我們已知其最短路徑的點,U集中的點是我們還未知其最短路徑的點。因此初始時刻,S集中只有一個我們選定的起始點,U集中是除了起始點意外的所有點;而最終時刻,S集中應該包含所有的點,U集爲空集。
  2. 從最後加入S集的u點出發,選出到U集中最短的那個點nextVertex,將nextVertex點加入S集,並從U集中移除nextVertex點。
  3. 更新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;
}
發佈了47 篇原創文章 · 獲贊 32 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章