引入
迪科斯彻提出了著名的单源最短路径求解算法——Dijkstra算法。
Dijkstra算法是解决单源最短路径问题的贪心算法,它先求出长度最短的一条路径,再参照该最短路径求出长度次短的一条路径,直到求出从源点到其他各个顶点的最短路径。
Dijkstra算法的基本思想是首先假定源点为u,顶点集合V被划分为两部分:集合S和V-S。初始时S中仅含有源点u,其中S中的顶点到源点的最短路径已经确定。集合V-S中所包含的顶点到源点的最短路径的长度待定,称从源点出发只经过S中的点到达V-S中的点的路径为特殊路径,并用数组dist[]记录当前每个顶点所对应的最短特殊路径长度.
Dijkstra算法采用的贪心策略是选择特殊路径长度最短的路径,将其连接的V-S中的顶点加入到集合S中,同时更新数组dist[]。一旦S包含了所有顶点,dist[]就是从源到所有其他顶点之间的最短路径长度。
算法步骤:
- 数据结构。设置地图的带权郐接矩阵为G.Edge[][],即如果从源点u到顶点i有边,
就令G.Edge[u][i]等于<u,i>的权值,否则G.Edge[u][i]=∞(无穷大);采用一维数组dist[i]来记录从源点到i顶点的最短路径长度;采用一维数组p[i]来记录最短路径上i顶点的前驱。 - 初始化。令集合S={u},对于集合V-S中的所有顶点x,初始化dist[1]=G.Edge[u][i],
如果源点u到顶点i有边相连,初始化p[i]=u,否则p[i]=-1。 - 找最小。 在集合V-S中依照贪心策略来寻找使得dist[j]具有最小值的顶点t,即
dist[t]=min (dist [ j ] | j属于V-S集合),则顶点t就是集合V-S中距离源点u最近的
顶点。 - 加入S战队。将顶点t加入集合S中,同时更新V-S。
- 判结束。如果集合V-S为空,算法结束,否则转6。
- 借东风。在 3 中已经找到了源点到t的最短路径,那么对集合V-S中所有与顶点
t相邻的顶点j,都可以借助t走捷径。如果dis[j>dist[t]+G.Edge[]Ii], 则
dist[i]=dist[t]+G.Edge[ t ][ i ],记录顶点j的前驱为t,即p[i]=t,转3。
参考代码
运行结果:
算法分析:
算法优化:
下面是优先队列和链式前向星的优化:
代码分析:易知每次寻找最小值都是在V-S中寻找的,第一次直接是源点不用寻找,然后更新dist,并将其加入到队列中,第二次是从队列中弹出一个最小的(不在队列中的V-S点不用考虑,因为他们都是无穷大,而我们要找的是最小值,),然后继续更新dist,每次在更新时,如果某个结点的dist为无穷大,则说明之前没有加入过,将其加入即可.然后如果在最小值的加入下该点的dist更小了,则更新dist和p.
(队列中可能点会重复,目前还没发现有影响.有更好想法的记得可以分享交流下哦)