1. 程式人生 > >迪傑斯特拉(優先佇列優化)

迪傑斯特拉(優先佇列優化)

使用鄰接矩陣實現的dijkstra演算法的複雜度是O(V²)。使用鄰接表的話,更新最短距離只需要訪問每條邊一次即可,因此這部分的複雜度是O(E).但是每次要列舉所有的頂點來查詢下一個使用的頂點,因此最終複雜度還是O(V²)。在|E|比較小時,大部分的時間都花在了查詢下一個使用的頂點上,因此需要使用合適的資料結構進行優化。

需要優化的是數值的插入(更新)和取出最小值兩個操作,因此使用堆就可以了。把每個頂點當前的最短距離用堆來維護,在更新最短距離時,把對應的元素往根的方向移動以滿足堆的性質。而每次從堆中取出的最小值就是下一次要用的頂點。這樣堆中的元素共有O(V)個,更新和取出的操作有O(E)次,因此整個演算法的複雜度是O(ElogV)。
下面是使用STL的priority_queue實現。在每次更新時往堆裡插入當前最短距離和頂點的值對。插入的次數是O(E)次,當取出的最小值不是最短距離的話,就丟棄這個值。這樣整個演算法也可以在同樣的時間內完成。

struct edge {int to,cost;};
typedef pair<int,int> P;  //first是最短距離,second是頂點的編號
int V; //頂點個數
vector<edge> G[MAXV];
int d[MAXV];

void dijkstra(int s)
{
    priority_queue<P,vector<P>,greater<P> > que;
    memset(d,INF,sizeof d);
    d[s] = 0;
    que.push(P(0,s));  //把起點推入佇列
    while(!que.empty())
    {
        P p = que.top(); que.pop();
        int v = p.second;  //頂點的編號
        if (d[v] < p.first) continue;       //當d[v]比已在集合中的點與未在集合中的點的距離大的時候,更新dis陣列
        for(int i = 0; i < G[v].size(); i++)   
        {
            edge e = G[v][i];
            if (d[e.to] > d[v] + e.cost)
            {
                d[e.to] = d[v] + e.cost;    //更新
                que.push(P(d[e.to],e.to));
            }
        }
    }
}