Dijkstra's Algorithm分析以及其优化
2017-07-25 21:57
127 查看
Dijkstra's Algorithm
传统的Dijkstra:
适用于单源无负权边最短路问题。
算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。
U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,
若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;
若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,
则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
传统dijkstra的不足之处:
(1)用邻接矩阵arcs来存储网络图,其存储量为
NxN。对于大型稀疏矩阵,这将耗费大量资源存储那些
无意义的矩阵元素。
(2)当从未标记节点集合T选定下一个节点vj作
中间节点后,在更新操作过程中,需要扫描所有的未标
记节点并进行比较更新。而未标记节点集合T中往往
包含大量与中间节点V;不直接相连的节点。
(3)在选择下一个最短路径节点作为中间节点时,
需要比较所有的未标记节点。而这个中间节点往往包含
在与已标记节点S集合的所有节点邻接的节点中。
(4)在算法的每次迭代中,由于未标记节点以无序
的形式存放在一个链表中或一个数组中.每次选择最短
路径节点都必须将所有未标记节点扫描一遍,当节点数
目很大时,这无疑将成为制约计算速度的关键冈素。
基于优先队列的优化
完全优化后空间复杂度可以从O(N*N)到O(4*N+E),时间复杂度可以从O(N*N)到O(n*(logN+E),具体复杂度分析不在此解析,详情可见参考论文。
在此只是在时间复杂度上有一定的优化,空间复杂度的优化可以用邻接表进行对边的存储。堆优化以及空间优化将在后续更新。
本文参考:王战红1 孙明明2姚 瑶3《Dijkstra算法的分析与改进》的论文。
传统的Dijkstra:
适用于单源无负权边最短路问题。
算法步骤:
a.初始时,S只包含源点,即S={v},v的距离为0。
U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,
若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;
若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,
则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
//核心代码: void Dijkstra(int s,int t)//s为起点 {//t为终点 int temp, k; ans=-1; for (int i=0; i<n; i++)//对起点邻点操作 { dis[i]=map[s][i]; vis[i]=0; } dis[s]=0; vis[s]=1;//说明s点已被标记 for (int i=0; i<n; i++) { temp = inf;//inf为超大的数 for (int j=0; j<n; j++) { if(vis[j]==0 && temp > dis[j]) {//j没有被标记且是已知点最小的 k=j; temp=dis[j]; } } if(temp == inf) //说明全被标记 break; vis[k]=1; for (int j=0; j<n; j++) {//看通过k点是否会取得更小值 if(dis[j] > dis[k] + map[k][j]) dis[j]=dis[k]+map[k][j]; } } if(dis[t]!=inf) ans = dis[t]; }
传统dijkstra的不足之处:
(1)用邻接矩阵arcs来存储网络图,其存储量为
NxN。对于大型稀疏矩阵,这将耗费大量资源存储那些
无意义的矩阵元素。
(2)当从未标记节点集合T选定下一个节点vj作
中间节点后,在更新操作过程中,需要扫描所有的未标
记节点并进行比较更新。而未标记节点集合T中往往
包含大量与中间节点V;不直接相连的节点。
(3)在选择下一个最短路径节点作为中间节点时,
需要比较所有的未标记节点。而这个中间节点往往包含
在与已标记节点S集合的所有节点邻接的节点中。
(4)在算法的每次迭代中,由于未标记节点以无序
的形式存放在一个链表中或一个数组中.每次选择最短
路径节点都必须将所有未标记节点扫描一遍,当节点数
目很大时,这无疑将成为制约计算速度的关键冈素。
基于优先队列的优化
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<stack> #include<queue> #include<vector> using namespace std; #define INF 0x3f3f3f3f //定义一个很大的数 struct Node { int num,val; //存放结点编号和到初始点的距离 } nod; priority_queue<Node> qq;; //优先从小到大 bool operator < (Node a,Node b) { if(a.val == b.val) return a.num>b.num; return a.val>b.val; //先出小 } int book[100]; //检查这个点是否用过 int dis[100]; //到原点最短距离 int D[100][100]; //记录路径长度 int V,E; int main() { int a,b,d; while(cin>>V>>E && V&& E) //输入顶点数和边数 { while(!qq.empty()) qq.pop(); //清空 memset(book,0,sizeof(book)); memset(D,-1,sizeof(D)); for(int i=0; i<E; i++) { cin>>a>>b>>d; D[a][b] = D[b][a] = d; } for(int i=2; i<=V; i++) dis[i]=INF; dis[1]=0; nod.num=1; nod.val=0; qq.push(nod); //将起点放入队列 while(!qq.empty()) //不为空时 { for(int i=2; i<=V; i++) { if(D[qq.top().num][i] != -1 &&dis[i]>dis[qq.top().num] + D[qq.top().num][i]) { dis[i]=dis[qq.top().num] + D[qq.top().num][i]; nod.num=i; nod.val=dis[i]; qq.push(nod); } } qq.pop(); } for(int i=1; i<=V; i++) { cout<<"初始点到"<<i<<"点的距离为:"<<dis[i]<<endl; } } return 0; }
完全优化后空间复杂度可以从O(N*N)到O(4*N+E),时间复杂度可以从O(N*N)到O(n*(logN+E),具体复杂度分析不在此解析,详情可见参考论文。
在此只是在时间复杂度上有一定的优化,空间复杂度的优化可以用邻接表进行对边的存储。堆优化以及空间优化将在后续更新。
本文参考:王战红1 孙明明2姚 瑶3《Dijkstra算法的分析与改进》的论文。
相关文章推荐
- 13 算法/分析方法的优化以及总结
- 阿里云大数据MaxCompute计算资源分布以及LogView分析优化
- 怎么选择关键词以及关键词分析优化
- Android应用内存泄露分析以及优化方案
- MongoDB涉及的业务比较慢--慢查询优化分析案例--以及参数说明
- ViewFlipper源码分析以及通过view复用优化viewFlipper用法
- Mustache php 版开源项目 流程 性能分析 以及优化
- 快速排序的复杂度分析以及使用插入排序优化的快速排序
- MySQL的SQL执行性能分析以及性能优化策略和步骤
- 阿里云大数据MaxCompute计算资源分布以及LogView分析优化
- App运行速度分析以及初步优化方案
- 选择网站关键词以及关键词分析优化
- 素数筛选以及优化分析
- sensor:gsensor的流程以及优化分析
- Android 性能优化之优秀工具以及分析
- MySQL优化系列(五)--数据库存储引擎(主要分析对比InnoDB和MyISAM以及讲述Mrg_Myisam分表)
- C++拷贝构造函数、无名临时对象以及NRV优化分析
- 阿里云大数据MaxCompute计算资源分布以及LogView分析优化
- 冒泡排序的分析以及优化
- mysql优化Analyze Table 以及批量分析表的命令