[最短路]使用优先队列优化的Dijkstra算法
2015-08-10 14:42
337 查看
用邻接矩阵的Dijkstra算法的代码:
使用邻接矩阵实现的dijkstra算法的复杂度是O(V²)。使用邻接表的话,更新最短距离只需要访问每条边一次即可,因此这部分的复杂度是O(E).但是每次要枚举所有的顶点来查找下一个使用的顶点,因此最终复杂度还是O(V²)。在|E|比较小时,大部分的时间都花在了查找下一个使用的顶点上,因此需要使用合适的数据结构进行优化。
需要优化的是数值的插入(更新)和取出最小值两个操作,因此使用堆就可以了。把每个顶点当前的最短距离用堆来维护,在更新最短距离时,把对应的元素往根的方向移动以满足堆的性质。而每次从堆中取出的最小值就是下一次要用的顶点。这样堆中的元素共有O(V)个,更新和取出的操作有O(E)次,因此整个算法的复杂度是O(ElogV)。
下面是使用STL的priority_queue实现。在每次更新时往堆里插入当前最短距离和顶点的值对。插入的次数是O(E)次,当取出的最小值不是最短距离的话,就丢弃这个值。这样整个算法也可以在同样的时间内完成。
相对于Bellman-Ford的O(VE)的复杂度,Dijkstra的复杂度是O(ElogV),可以更加高效地计算最短路的长度。不过需要注意的一点:当图中存在负边的情况下,Dijkstra算法就无法正确求解问题,还是需要使用Bellman-Ford算法。
int cost[RANGE][RANGE]; int d[RANGE]; bool used[RANGE]; int n,m; //顶点数,边数 void Dijkstra( int s ) { int i,v,u; for( i=1; i<=n; ++i ) { used[i]=false; d[i]=cost[1][i]; } d[s]=0; while( true ) { v=-1; for( u=1; u<=n; ++u ) if( !used[u] && ( v==-1 || d[u]<d[v]) ) v=u; if( v==-1 ) break; used[v]=true; for( u=1; u<=n; ++u ) d[u]= min( d[u],d[v]+cost[v][u] ); } }
使用邻接矩阵实现的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; 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)); } } } }
相对于Bellman-Ford的O(VE)的复杂度,Dijkstra的复杂度是O(ElogV),可以更加高效地计算最短路的长度。不过需要注意的一点:当图中存在负边的情况下,Dijkstra算法就无法正确求解问题,还是需要使用Bellman-Ford算法。
相关文章推荐
- 流量控制与拥塞控制
- POJ 1011 Sticks 经典的dfs+剪枝
- 九度OJ 题目1468:Sharing
- 相机标定
- Android 内存优化总结
- 爱福窝在线装修设计软件测评
- C++ 的那些坑 (Day 1)
- 发送带附件的邮件
- Linux磁盘与文件系统管理(4)
- NOIP2009模拟考试总结
- OSGI中引用外部包的几种方法
- 电信宽带没有路由器也能上无线网
- 源码安装的mysql新增federated引擎
- PAT 1015. Reversible Primes (20)
- 线段树专题—HDU2795 Billboard
- 什么是filtercache
- 知识点三:PreferenceFragment的用法
- AngularJs 常用函数
- java使用memcached2--集群部署
- codevs 1012 最大公约数和最小公倍数问题