前文已经基于公开数据,获得了南京的全域高速公路的路网数据,这些以node / link文件表征的道路网络不仅延续了osm地图中所包含的经纬度、名称、容量等信息 ,还包含了一个重要的道路等级字段 “link_type_name”。
交通部门一般以高速公路、国省干道、城市道路、乡道农路作为区分,进行交通执法及管理。作为在高速公路领域混饭吃的,本系列计划以南京高速公路路网(也就是下图)为例,展示路径规划的一种思路。
对于交通使用者来说,如何从起点去往终点,有多种备选的路径。如果使用node / link表征的道路网络,那么提供给用户的就是类似于“187 - 666 - 1765 -4567 ”这样的一串node编号,告诉从点187出发的用户应该去666号点位,再到1765号点位,最后就能到终点4567了。对应的, 187点到666点之间也必须有路,而且不需要经过额外的点,这就是完成这次出行所需走过的路段,在link文件里也会找到对应的路段编号、长度等信息。
因为城市道路足够复杂,所以会出现如下图的情况:
狗窝去猫窝有两条路,
其中一条是直达的,9km
另一条要从麦当劳和火锅店经过,反而只需要“2+3+1”,6km。
这说明:
①存在有效的link,不代表这就是link起终点间的最短路线;
②必须规定,在表征路径时,node编号串就与link直接对应,才能避免出现差错;
③只有搜索了所有的可能,才能确定最短路是哪一条。
**
如何在路网中,提供起终点,找到两点之间的最短路径呢?
dijkstra算法是绕不过去的一座大山
求“带权有向图的最短路径问题”一般可分为两类:
一是单源最短路径,即求图中某一个顶点到其它顶点的最短路径,可以通过经典的 Dijkstra(迪杰斯特拉)算法求解;
二是求每对顶点间的最短路径,可通过Floyd(弗洛伊德)算法来求解,这个我也会,但是本文主要是在指定起终点的路径规划层面玩耍,所以不讲了。
Dijkstra算法的目的是寻找单起点最短路径,其策略是贪心加非负加权队列。
Dijkstra算法步骤如下:
它按照距离起点的远近顺序,逐步确定到各个顶点的最短路径。具体来说,算法首先找到距离起点最近的顶点,并确定它们之间的最短路径;然后,它接着寻找下一个最近的顶点,依此类推。在第 i 次迭代之前,算法已经确定了到达最近的 i − 1 个顶点的最短路径,这些顶点及其路径构成了原图的一个子图,形成一棵以起点为根的树(这也是做最短路的副产品)。
由于图中所有边的权重都为非负,算法能够保证每次迭代找到的是当前可达顶点中距离起点最近的一个。这些待选顶点,称为“边缘顶点”,位于已构建的子树的外围,也就是距离“确定的树”一步之遥的顶点。其他顶点与树中顶点要想发生关联,还得经过额外的顶点。这是我们就暂时把它们的连接权重假设为无限大,意思是,他们可能重演前面的“猫窝狗窝现象”,所以暂不考虑。
为了求出下一个最接近起点的顶点,Dijkstra算法计算每个边缘顶点至其最近的树内顶点的距离(即该边的权重),并将此距离与从起点到该树内顶点的已知最短路径长度相加。在所有这些候选顶点中,算法选择总和最小的顶点作为下一个最近顶点。
Dijkstra算法的核心在于,通过仅对这些特定的候选路径进行比较,就可以有效地找到最短路径。
为了简化算法的实施过程,我们为每个顶点引入两个辅助标记。
第一个标记是一个数值标记 d ,它记录了从算法开始到当前为止,从起点到该顶点的最短路径长度。随着算法的进行,当新的顶点被加入到树中时,d 的值更新为从起点到这个新顶点的最短路径长度。
第二个标记则记录了该路径上的倒数第二个顶点,即当前构建的树中该顶点的父节点(对于起点以及那些尚未与树中的顶点直接相连的顶点,这个标记不必指定)。
有了这两个标记后,寻找下一个最近顶点 u * 变得相对直接:
仅需在所有边缘顶点中找到具有最小 d 值的顶点即可,而这个查找过程的顺序并不重要。这样,这两个标记极大地简化了算法的步骤,使得确定最短路径的过程更加高效和直观。
比如上图,我要找从a点出发去e点的最短路:
第一步,一开始所谓的“确定的树”上只有a点,b点、d点是“候选备胎”,a-b距离是3,a-d距离是7,所以果断选a-b往下探索,
b(a,3)表示,如果要回溯,b点的前一个点是a点,距离是3
对b点来说,“候选备胎”是c点、d点,b点去d点距离更近,所以:
d(b,5)来了,d点到a点的最短路长度是5 ,经过b点,比直接a点到d点的7更近。
此时,a点的“确定的树”上有a、b、d三个成员了
还剩下c点、e点
c点、e点到“确定的树”距离相等,但是c点“巴结的”是b点,距离起点更近,所以c点先来,最后e点。
此时,从a点出发,所有的点都被纳入了“确定的树”上了。
也就是说,现在我们获得了路网上每一个点到a点的最短路径,当然也就包括了我们想要的那个终点到a点的最短路径。
e(d,9)说明,a点到e点的最短距离是9
路线是e - d - b -a
最短路的常用算法,万变不离其宗,对于复杂路网来说,我们只是会试图用一些小方法来缩短求解时间,或者去除一些不必要的计算,但是基本原理几乎也就这样了。
基于以上的原理和数据,我测试了利用dijkstra算法在南京实际高速公路路网中搜索最短路的算法,请移步下一篇