单源最短路深度分析

单源最短路深度分析

一.前言:

1.定义:

E:边的数量

V:点的数量

S:源点

稠密图:E=θ(V*V

稀疏图:E=θ(V

圈:代表从自身出去至少一个点再回到自身(egv->a->...->v

环:代表有自身到自身的路线(egv->v)。

 

2.此分析,Map(地图)采用邻接表存储,邻接矩阵空间时间复杂度均上升一个数量级。

 

3.所有点到源点的距离用数组存储,记为Di(意为i点到源点S距离)。

 

4.此分析主要分析SPFADijkstra和拓扑排序在各种情况下的选择问题,不考虑Bellman-ford算法(实在太坑爹)。

 

5.不考虑负圈(更本不存在最短路。。。),亦不考虑环。

 

PS:拓扑排序在最短路方面的主要功能为以OE+V)的时间判断有无圈圈,在此使用是因为在无圈且出发点为源点的情况下其性能远超DijkstraSPFA

PS:不要迷信SPFA在任何时候都快,说它是最快的算法是因为SPFA可以根据各种情况作出调整,使其成为最快。

 

二.Dijkstra算法简介:

1.算法流程:

初始化所有点到源点S的距离为无穷大,初始化源点S到源点S的距离为0

Map中找到所有点距离源点S最近的未被锁定(代表此点并未在之前被使用)的节点K,用K更新所有与K相连的节点并锁定K(代表K被使用过),知道所有点都被锁定,算法结束。

 

2.时间复杂度:

OV*V+E,第一个V代表总共要锁定V个点,第二个V代表要找到距离源点S最近的点需要V次(也就是扫过所有的点)。并此算法保证每条边只用一次。

 

3.空间复杂度:

OMaxV,E))

 

4.优点:

编程快,如果采用邻接矩阵存Map,则只需短短几行。

 

5.缺点:

无法处理带负权的边

 

三.SPFA算法简介

1.算法流程:

此算法需要队列。

初始化所有点到源点S的距离为无穷大,初始化源点S到源点S的距离为0,将源点S进队。

如果队列非空,则将队首元素(节点K)出队,更新与K相连的所有节点ai0<=i<=K相连的节点数),如果ai被更新并且不在队列中,则将ai入队。直到队列为空,算法结束。

 

2.时间复杂度:

OT*V+T*E),此算法不保证每个点只出队列一次,所以T代表每个点最多出队列的次数(不大于V,一般情况T都是常数级)。因每个点多次出队,所以每条边就不止使用一次,

 

3.空间复杂度:

OMaxV,E))

 

4.优点:

BFS经典算法;

可处理带负边的各种图;

可找到负圈,如果节点K的出队次数大于V,则必然存在负圈

 

5.缺点:

在稠密图中,尤其是带负权的图中,T很可能会退化到V,使其时间复杂度上升一个数量级;不带负权的图中,T也可能发生严重退化。

 

四.拓扑排序算法简介(仅能在无圈且出发点为源点的情况下使用)

1.算法流程

此算法需要队列。

此算法需要维护一个入度数组Ri,代表第i个节点有几条入边(比如v->w,则w有一个入边vRw至少为1)。

初始化所有点到源点S的距离为无穷大,初始化源点S到源点S的距离为0,初始化所有点的入边数Ri,将Ri0的节点加入队列。

如果队列非空,则将队首元素(节点K)出队,更新与K相连的所有节点ai0<=i<=K相连的节点数),在Map上删去K点以及K的出边,同时Ri1(不用显式的删除KK的出边,Ri1就相当于删除操作),如果Ri==0,则将节点i加入队列。直到队列为空,算法结束。

 

2.时间复杂度:

OV+E),此算法保证每个节点、每条边使用一次。

 

4.空间复杂度:

OMaxV,E))

 

5.缺点:

无法处理带圈图;

无法处理当源点非起始点之一的图(或者删除所有源点S到不了的点及其出边)。

 

五.SPFA算法优化:

为什么只优化SPFA算法?因为SPFA算法可以优化出Dijkstra和拓扑排序,甚至更好。

 

1.SLF优化:

设队首元素为i,队列中要加入的元素为j,当Dj<=Di时加到队首,反之加到队尾。

虽不改变时间下界,但经验证明能提速30%以上。

 

2.LLL优化(极不常用,在此仅介绍):

维护队列中所有点到源点的平均值d,设队首元素为i,每次出队时,当Di>d时,将队首元素移至队尾,否则出队。

 

3.优先队列的普通实现:

入队O1),出队OV)。

此优化使SPFADijkstra算法占优的图中具有和Dijkstra算法同等时间下界(但速度绝对比Dijkstra快)。(原理:在不含负边的图中,从优先队列中出去的点再也不会进入队列,这和Dijkstra的锁点效果一样)

 

4.优先队列的堆实现:

入队OlgV),出队OlgV.

在此推荐使用配对堆。

如果使用二叉堆,需要考虑当更新优先队列中的节点i的最短距离时,需要调整节点i在二叉堆中的位置。

 

5.加上入度数组的优化:

更新节点i后,当i的入度为0时再入队(呃,好吧,思路一样,其实就是拓扑排序……)

 

六.算法选择:

1.无圈图:

      a) 源点是出发点之一:

               i. 拓扑排序:OV+E=OE

               ii. SPFA+入度数组:O(V+E)=O(E)

      b) 其余与有圈图一样。

 

2.有圈图:

      a) 稠密图:

                i. 无负边:

                       1. DijkstraOV*V+E=O(E)

                       2. SPFA+优先队列的普通实现+SLF优化(推荐):OV*V+E=O(E)

                ii. 有负边:

                       1. SPFA+优先队列的普通实现+SLF优化:O(T*V*V+T*E)=O(V*E)T退化到V

        b) 稀疏图:

               i. 无负边:

                       1. SPFA+优先队列的堆实现:O(V*lgV+E*lgV)=O(E*lgV)

               ii. 有负边:

                       1. SPFA+优先队列的堆实现:O(T*V*lgV+T*E*lgV)=O(E*lgV)T保持常数级。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值