迪傑斯特拉(優先佇列優化)
阿新 • • 發佈:2018-12-22
使用鄰接矩陣實現的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)); } } } }