dijkstra算法与优先队列
这是鄙人的第一篇技术博客,作为算法小菜鸟外加轻度写作障碍者,写技术博客也算是对自己的一种挑战和鞭策吧~
言归正传,什么是dijkstra算法呢?
-dijkstra算法是一种解决最短路径问题的简单有效的方法~也算是一种非常naive&effcient的最优化算法吧~
最短路径问题

如上图,从点A->点F,最短路径为A->C->D->F,Min=3+3+3=9
假设用暴力深度搜索遍历所有路径的话,时间复杂度O将会是指数级的(NP-hard Problem)~
dijkstra算法
作为我最喜欢的经典算法之一,dijkstra算法并没有用到高深的图论和拓扑学的知识,
它的核心思想也很简单:贪心法+动态规划
下面贴出维基百科上的伪代码:
1 function Dijkstra(Graph, source):
2 dist[source] := 0 // Distance from source to source
3 for each vertex v in Graph: // Initializations
4 if v ≠ source
5 dist[v] := infinity // Unknown distance function from source to v
6 previous[v] := undefined // Previous node in optimal path from source
7 end if
8 add v to Q // All nodes initially in Q (unvisited nodes)
9 end for
10
11 while Q is not empty: // The main loop
12 u := vertex in Q with min dist[u] // Source node in first case
13 remove u from Q
14
15 for each neighbor v of u: // where v has not yet been removed from Q.
16 alt := dist[u] + length(u, v)
17 if alt < dist[v]: // A shorter path to v has been found
18 dist[v] := alt
19 previous[v] := u
20 end if
21 end for
22 end while
23 return dist[], previous[]
24 end function
贪心的思想体现在 Line12: u := vertex in Q with min dist[u]
从所有的待优化的点Q中找出距离起点最近的点u~
动态规划的思想体现在 Line16-20: 最优表达式为 dist[v] := min{dist[v],dist[u] + length(u, v)}
即如果存在dist[start->u->v]<dist[start->v],则将路径更新~
在dijkstra算法里,每个点的路径可能会被更新N次(length(Q)>N>=0),并不存在一个明确的状态递进。
因此,如何保证在更新N次后,一定能求出最优解,是算法的核心问题~
答案就是贪心法,运用贪心法优化更新的顺序,确保从小到大,更新一遍Q即求出最优解。
优先队列+dijkstra算法
让我们分析一下dijkstra算法的时间复杂度:
总时间复杂度=找最短距离 u := vertex in Q with min dist[u] 的时间复杂度 +
更新距离 dist[v] := min{dist[v],dist[u] + length(u, v)} 的时间复杂度
对于一个无向图G(V,E)来说,
找最短距离的时间复杂度为O(|V|*|V|)(共循环V次,每次V个点),考虑到Q每次递减1,实际复杂度为O(|V|^2/2);
由于图共有E条边,每条边最多被更新2次(1条边2个端点),因此更新距离的时间复杂度为O(2*|E|)。
因此,总时间复杂度=O(2*|E|+|V|^2/2)
然后,实际情况中经常会遇到 |V|^2>>|E| 的稀疏图,即O(2*|E|+|V|^2/2)=O(|V|^2/2)~
因此,如果我们能够优化 findMIN部分,即可大大优化稀疏图下的dijkstra算法~
findMIN的部分优化方法很多,最简单的就是用二分搜索O(logN)代替线性搜索 O(N)~
这里我们将集合Q转化成一个优先队列(priority queue),这样findMIN的时间复杂度变成了O(1),而每次更新priority queue需要花费O(log|V|)~
综上,采用优先队列之后,总时间复杂度=O(2*|E|+|V|*log|V|),
这样的优化对于稀疏图(|V|^2>>|E|)来说,尤为有效~
P.S. 本文仅想谈谈鄙人对dijkstra算法的一些浅见,即粗浅又不够系统,还望各位大牛多多指点~
下一篇博文将会拓展 优先队列(priority queue) 的内容(如果鄙人木有被板砖拍死的话^ ^)
最后贴上鄙人用python实现的dijkstra+priority queue的demo,经测试在G(V=2000,E=10000)时,priority queue能够提升近1倍的运算速度:
# -*- coding: utf-8 -*-
"""
Created on Sun Aug 24 2014 @author: Sperling
"""
import random,time,heapq ###采用优先队列的dijkstra算法###
def dijkstra_pq(conj):
##初始化 各点到起点的最优距离(dis)##
dis=[0]
dis.extend([-1]*(len(conj)-1))
for c in conj[0]:
dis[c[1]]=c[0]
##初始化 待优化的点(排除起点)##
pool=[i for i in range(1,len(conj))]
##初始化 路径记录列表##
pre=[0 if dis[i]>=0 else -1 for i in range(len(conj))]
pre[0]=-1
##初始化 优先队列(Fibonacci heap)##
pq=[(dis[i],i) for i in range(1,len(conj)) if dis[i]>=0]
heapq.heapify(pq) while len(pool)>0:
##找出待优化池中的最短路径点(argmin)##
argmin=-1
while (argmin not in pool) and len(pq)>0:
MIN,argmin=heapq.heappop(pq)
##将最短路径点(argmin)从池中捞出##
if argmin not in pool:
break
else:
pool.remove(argmin)
##更新与argmin直接连通的点<->起点的最短路径##
for c in conj[argmin]:
if c[0]+MIN<dis[c[1]] or dis[c[1]]<0:
dis[c[1]]=c[0]+MIN
pre[c[1]]=argmin
heapq.heappush(pq,(dis[c[1]],c[1])) return dis,pre ###原始dijkstra算法###
def dijkstra(conj):
##初始化 各点到起点的最优距离(dis)##
dis=[0]
dis.extend([-1]*(len(conj)-1))
for c in conj[0]:
dis[c[1]]=c[0]
##初始化 待优化的点(排除起点)##
pool=[i for i in range(1,len(conj))]
##初始化 路径记录列表##
pre=[0 if dis[i]>=0 else -1 for i in range(len(conj))]
pre[0]=-1 while len(pool)>0:
##找出待优化池中的最短路径点(argmin)##
MIN,argmin=1000000,-1
for i in pool:
if dis[i]>0 and MIN>=dis[i]:
MIN,argmin=dis[i],i
##将最短路径点(argmin)从池中捞出##
if argmin<0:
break
else:
pool.remove(argmin)
##更新与argmin直接连通的点<->起点的最短路径##
for c in conj[argmin]:
if c[0]+MIN<dis[c[1]] or dis[c[1]]<0:
dis[c[1]]=c[0]+MIN
pre[c[1]]=argmin return dis,pre ###回溯最优路径###
def trace(pre,p):
route=[]
while p>=0:
route.append(p)
p=pre[p]
return route[::-1] ###构造随机图,不能保证图的连通性###
def randomroute(nV,nE):
##构造nE*nE的随机关联矩阵(mat),其中有2*nV个点是连通的##
mat=[[0 if i==j else -1 for i in range(nV)] for j in range(nV)]
rE=random.sample(xrange(nV*(nV-1)/2),nE)
for k in rE:
i,j=0,k
while i<j:
i+=1
j-=i
i+=1
r=random.randint(1,100)
mat[i][j],mat[j][i]=r,r
##将随机关联矩阵(mat) 转化为 每个顶点的直接连通点列表(route)##
route=[]
for i in range(len(mat)):
route.append([])
for j in range(len(mat[i])):
if mat[i][j]>0:
route[i].append((mat[i][j],j)) return route if __name__=='__main__':
conj=randomroute(2000,10000)
t0=time.clock()
dis,pre=dijkstra(conj)
t1=time.clock()
print 'time_cost dijkstra:%f'%(t1-t0)
print dis[len(conj)-1]
print trace(pre,len(conj)-1) t0=time.clock()
dis,pre=dijkstra_pq(conj)
t1=time.clock()
print 'time_cost dijkstra+priority queue:%f'%(t1-t0)
print dis[len(conj)-1]
print trace(pre,len(conj)-1)
dijkstra算法与优先队列的更多相关文章
- dijkstra算法之优先队列优化
github地址:https://github.com/muzhailong/dijkstra-PriorityQueue 1.题目 分析与解题思路 dijkstra算法是典型的用来解决单源最短路径的 ...
- Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解
/* Dijkstra算法用优先队列来实现,实现了每一条边最多遍历一次. 要知道,我们从队列头部找到的都是到 已经"建好树"的最短距离以及该节点编号, 并由该节点去更新 树根 到其 ...
- HDU 1535 Invitation Cards(逆向思维+邻接表+优先队列的Dijkstra算法)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1535 Problem Description In the age of television, n ...
- 基于STL优先队列和邻接表的dijkstra算法
首先说下STL优先队列的局限性,那就是只提供入队.出队.取得队首元素的值的功能,而dijkstra算法的堆优化需要能够随机访问队列中某个节点(来更新源点节点的最短距离). 看似可以用vector配合m ...
- Dijkstra算法(朴素实现、优先队列优化)
Dijkstra算法只能求取边的权重为非负的图的最短路径,而Bellman-Ford算法可以求取边的权重为负的图的最短路径(但Bellman-Ford算法在图中存在负环的情况下,最短路径是不存在的(负 ...
- 最短路模板(Dijkstra & Dijkstra算法+堆优化 & bellman_ford & 单源最短路SPFA)
关于几个的区别和联系:http://www.cnblogs.com/zswbky/p/5432353.html d.每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个(草儿家到 ...
- ACM: HDU 1874 畅通工程续-Dijkstra算法
HDU 1874 畅通工程续 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Desc ...
- 最短路径算法之Dijkstra算法(java实现)
前言 Dijkstra算法是最短路径算法中为人熟知的一种,是单起点全路径算法.该算法被称为是“贪心算法”的成功典范.本文接下来将尝试以最通俗的语言来介绍这个伟大的算法,并赋予java实现代码. 一.知 ...
- [图论]Dijkstra 算法小结
Dijkstra 算法小结 By Wine93 2013.11 1. Dijkstra 算法相关介绍 算法阐述:Dijkstra是解决单源最短路径的算法,它可以在O(n^2)内计算出源点(s)到图中 ...
随机推荐
- Kindeditor单独调用单图上传增加预览
html代码: <p><input type="hidden" id="url1" name="IDCardPicture1&quo ...
- vue-cli -- > 项目基本构建的方法
本文档目的在于让对vue了解比较少的同学,能够快速搭建属于自己的vue项目.(window) 一.构建项目的前提条件 1.确保本机安装了node.js ^6 --> javascript 的服务 ...
- 酷狗音乐PC端怎么使用听歌识曲功能?
生活中很多时候会听到一些美妙的音乐,耳熟或者动听却不知道它的名字.就像第一眼看到你心动的那个她却不知她叫什么.移动端有酷狗音乐的听歌识曲.现在PC端也有了相同的功能,每当我们看到一部精彩影视剧听到美妙 ...
- UI5 Source code map机制的细节介绍
在我的博客A debugging issue caused by source code mapping里我介绍了在我做SAP C4C开发时遇到的一个曾经困扰我很久的问题,最后结论是这个问题由于Jav ...
- Radix Sort
为了完成二维数据快速分类,最先使用的是hash分类. 前几天我突然想,既然基数排序的时间复杂度也不高,而且可能比hash分类更稳定,所以不妨试一下. 在实现上我依次实现: 1.一维数组基数排序 基本解 ...
- 转载:手把手教你搭建 vue 环境
以下内容转自: https://segmentfault.com/a/1190000008922234 第一步 node环境安装 1.1 如果本机没有安装node运行环境,请下载node 安装包进行安 ...
- CoreData的学习
第一步:创建项目是勾选coredata,当然创建的时候没有勾选,之后还可以手动生产, 然后:创建数据库模型,及为其添加模型的属性. 然后生成模型文件: 注意⚠️:首先设置为Manual/None 不 ...
- 【转】DataURL在Web浏览器中的兼容性总结
IE8+,Firefox,Chrome,Opera,Safari 等现代浏览器普遍支持data URL IE8 data URL 最大长度限制为32k字节,超出无效.IE9+没有这个限制 IE只识别b ...
- 问题 A: E2 驾驭const
题目描述 引入了const关键词,用于指定“常”对象及“常”对象成员,提供了对数据的一种保护机制,这C++语言的特色之一.但由此,也引出了一些语法上的要求.这些语法要求,实际上有一套完善的原则,需要熟 ...
- 2017.9.29 web网上答题及其自动评测系统
1. 设计计一个网上答题及其自动评测系统,首先是试题页面的设计及其解答的提交, 其次是当提交解答之后,系统自动评阅并给出结果. 分析:需要两个jsp页面:一个是提交信息的页面,另一个是获取提交信息的页 ...