最短路径搜索方法对比—Dijkstra,Best-first和A* search

前言

由于最近在看最短路径方面的论文,就最短路径搜索算法,这里的最短路径是泛指的,不一定是距离也可能是行进时间、花费开销等,在这里我们用实际距离。最经典的并且常常作为其它改进算法的baseline的就是Dijkstra、Best-first以及A* search,因此深入理解这些方法对于后续的研究是很重要的。根据我自己的理解以及一些论文里的解释,我将对他们做一个简要的对比(只提取我认为重要的)。

评价函数(Evaluation function):这三种方法的最主要区别在于选取最短路径的下一个节点的评价方式不同,假如用函数f(n)=g(n)+h(n)来表示选取的评价指标,即每次选择值更小的作为下一个节点。

启发函数(heuristic function):其中h(n)为启发函数表示的是当前节点到目标节点之间形成路径的最小代价值。

 

Dijkstra算法

算法描述

这种经典算法相信大家都学习过,网上也有很多讲解,因此具体的过程就不再详细叙述,它从起始点开始,不断搜索最近的点并不断更新到起始点的最短距离,主要有三种状态{unreached,reached,settled},unreached指还未有到起点的距离值,reached指已经更新了到起点的距离值,settled指已经作为当前到起点的距离最小的点被选择。即f(n)=g(n)+h(n)中的h(n)为0,只考虑到起始点的距离(travel time)。

复杂度

采用数组存储距离为O(n^{2}),采用优先队列优化后为O(m+n\log m),对于一般为常数度的网络可以看作O(n\log n),最低为\Omega (n+m)

算法评价

这种算法由于采取的是遍历的方法,因此最终找到的最短路径一定是正确的最优解,但存在的问题如下图所示,从起点X开始到达接近我们真正要查询的终点V需要遍历很多与结果无关的点(深灰色点),导致复杂度变高,所以才会有后面的启发式算法来减少搜索空间。

Best-first

算法描述

Best-first是一种启发式的贪心算法,它的f(n)就等于h(n),和BFS(广度优先搜索)算法类似,区别在于它是启发式的不是全部遍历的,因此结果可能并不是最优的。它每次采用贪心机制只选择离自己最近的即f(n)最小的。大大减小了搜索范围。具体的一种实现方法如下(转自https://www.jianshu.com/p/617d4a47eac4):

  • 算法实现需要有两个优先队列Open和Closed,Open队列用来存放未遍历并将要被遍历的节点;Closed队列用来存放已经遍历过的节点。
  • 初始时将根节点放入Open队列中,此时Closed队列为空。
  • 开启算法循环(遍历代价最小的节点的所有子节点)
  • 1、 从Open队列中选出一个优先级最高的节点X(根据估价函数计算出来的),并生成子节点Y。
  • a. 如果Y不在Open队列和Closed队列中时(未被遍历过),通过估价函数计算出Y节点的估价,并将Y节点添加到Open队列中,并根据估价对Open队列中的节点进行排序。

  • b. 如果Y节点在Open队列中时,通过估价函数重新计算出Y节点的估价,并和Open队列中的Y节点的估价进行比较,如果估计高于Open队列中的Y节点的估价,替换Open队列中的Y节点的估价,并对Open队列中的节点重新排序。

  • c. 如果Y节点在Closed队列中时,通过估价函数计算出Y节点的估值,并和Closed队列中的Y节点的估价进行比较,如果高于Closed队列中的估价时,将Y节点从Closed队列中移除,并添加到Open队列中,并对Open队列进行排序。

  • 2、将节点X从Open队列中移除并添加到Closed队列中(X节点就应该是路径上的一个点,通过从最终点向上找父节点查到完整的路径)。
  • 3、循环上序操作直到找到目标点(算法找到目标点)或则Open队列中没有节点为止(算法未能找到结果)。

算法评价

上面这种算法是采用两个优先队列,closed作为最终的返回结果即K个最近的节点及距离,另一个open队列做类似于BFS的操作:对刚从队列中移除的top节点,遍历其邻接点并更新评价值,再加入到open队列中,相较于DIjkstra算法,大大减小了搜索的范围,对于大规模图时性能优化效果极佳。但存在的问题是找到的并不能保证是真正的最优解,即最短路径。

进一步优化

为了进一步减少搜索空间,可以对其进行剪枝操作,即维护两个值D_{min}D_{k}:D_{min}是当前closed队列中队顶元素的值-即最小值;D_{k}是当前找到的最近的第k个值。在不断进行广度遍历时当其值已经小于D_{min}时可以将其直接放到closed中,而当其父节点的值已经大于D_{k}时,无需在对其子节点做任何操作。这样就达到了剪枝的目的,使得优先队列的尺寸减小,减少内存空间并提高了优先队列效率。

 

A* search

Best first存在的问题是启发式函数设计的不好导致结果准确度较低,因此A星算法由两部分组成:f(n)=g(n)+h(n)。其中g(n)表示从起始节点到当前节点n的开销代价值;h(n)表示从当前节点到目标节点的=路径中所估算的最小开销代价。

算法描述

为了保证A星算法是最优的(optimal),即没有其他路径比搜索出来的结果更短,是和Dijkstra等价的,需要满足两点:(1)可容:是专门针对启发函数而言的,即启发函数的估计值必须小于等于当前节点到目标节点的实际代价开销,从而保证不会过高估计;(2)一致性:假设节点n的后续节点是v,一致性指从n到目标节点的代价开销小于等于从n到v的代价开销加上v到目标节点的开销。其中h(n)一般为估算值,估算的方法也有很多。I. Pohl. Bi-directional Search. In Machine Intelligence, volume 6, pages 124–140. Edinburgh Univ. Press, Edinburgh, 1971.这篇论文对此进行了详细的说明和论证。

如果用被examine的点和最终结果最短路径上的点的比值作为评价标准,我们可以看到,如果h(n)是精确的从当前节点n到目标节点的开销代价,那么被settle(examine)的点就恰好等于最短路径上的点,而且是最优解。A*算法通过启发式函数来进行goal-direction引导,使得搜索空间大大减小,如下图所示:最左边为DIjkstra算法的搜索范围,中间和右图分别是采用两种不同距离下界的A* search算法的搜索范围,且经过证明如果满足条件的启发函数h(n)越大搜索的范围越小。

 

 

 

©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页