地图寻路搜索

项目中集成了高德开放平台地铁图 JS API 传送门,经过长期的功能迭代,甲方提出了各种定制化需求来优化体验,而使用这种第三方SDK就很难满足;因此如果自己开发一套地铁线路图引擎,从功能和体验上达到完全可控,可完美满足用户需求;

技术分析

  • 画布大小,元素坐标点确认,需要开发一套管理台,标记地图大小、元素坐标位置、元素连接关系等,在此不多赘述
  • 线路图绘制,这个实现方式有很多,移动WEB通过纯JS<svg/>标签即可实现;如果采用RN技术栈,推荐使用react-native-svg第三方库实现;具体绘制实现思路轻点
  • 地图路径搜索,将整个地图的所有连接点保存成有向图,通过地图寻路算法快速找出最短路径,此次的重点就是如何实现寻路算法!


    image.png

重要概念

有向图

相对于无向图产生,无向图描述了所有顶点之间的连接关系,每两个顶点关系是双向的,而有相图不是,例如:A单向通向B,A->B,但反过来就不行;具体描述关系如下:


image.png

地铁线路图中所有的站点之间存在着连接关系,虽然说大部分情况前后站点连接是双向的关系,但不排除特殊情况下会出现单向连接,所以使用有向图来存储互相之间的关系比较稳妥。

广度优先(BFS)

广度优先遍历图的方式为,一次性访问当前顶点的所有未访问状态相邻顶点,并依次对每个相邻顶点执行同样处理,它是以一种类似波纹扩散的方式进行的,不断放大辐射半径,进而覆盖整张图。

深度优先(DFS)

深度优先遍历图的方式,同样会访问一个顶点的所有相邻顶点,不过深度优先的方式,首先访问一个相邻顶点,并继续访问该相邻顶点的一个相邻顶点,重复执行直到当前正在被访问的顶点出度为零,或者不存在未访问状态的相邻顶点,则回退到上一个顶点继续按照该深度优先方式访问。相对于广度优先访问,深度优先的方式更像是一条路走到黑,走不下去了再回到上个路口选择另外一条路。

Dijkstra算法

Dijkstra算法是按照广度优先(BFS)思想改进的搜索方案,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点s的距离)。
初始时,S中只有起点a;U中是除a之外的顶点,并且U中顶点的路径是”起点到该顶点的路径”。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;如发现路径更短的顶点,更新U中的顶点和顶点对应的路径。重复该操作,直到遍历完所有顶点。


Dijkstra动画示例

分析

按照广度优先的算法,像剥洋葱一样一层一层打开相邻顶点,直到找到目标顶点位置为止,虽然这种方案可以找到最短路近,但搜索较远距离的路径从性能上讲就比较耗时了,试想,很多反方向顶点都被打开参与搜索无疑比较费时。
同理,Dijkstra算法基于广度优先思路找到最短路近,但搜索较远距离的路径从性能上讲也比较耗时。
按照深度优先的算法,是一条路走到底,虽然说一旦找到目标顶点就马上停止,但不一定是最短路近,而快速搜索到目标顶点存在一定的运气成分,如果地图死胡同比较多的情况下也是比较费时。
有没有既不费时,又能找到相对较短路径的搜索算法?

A*算法

A*算法一种基于启发式探索的方法来提高Dijkstra算法的速度,在寻路的过程中,给每个节点绑定了一个估计值(即启发式),在对节点的遍历过程中是采取估计值优先原则,估计值更优的顶点会被优先遍历。所以启发函数的定义十分重要,显著影响算法效率。

启发函数

F(n) = G(n) + H(n)
G(n)表示由起点到顶点n的固定消耗,H(n)表示顶点n到终点的估计消耗,F(n)就表示由起点经过顶点n到达终点的总消耗;所以访问相邻顶点是以F(n)值较小优先遍历;
H(n)的计算方式有很多种,比如曼哈顿式H(n) = |dx|+|dy|,或者欧几里得式(两点距离)H(n) = sqrt(x^2 + y^2),本文采用欧几里得式;
按照启发函数,以路径损耗+预估损耗值优先的方式,当前顶点与目标顶点之间会越来越接近,达到减少探索范围,降低问题复杂度的目的;

实现流程

(1)从起点A开始,把它就加入到一个由顶点组成的 open list(开放列表) 中。open list 里的格子是路径可能会是沿途经过的,也有可能不经过。基本上open list是一个待检查的顶点列表。
(2)查看与起点A相邻顶点 (忽略障碍物或不可到达的顶点) ,加入到 open list中。把起点A设置为这些顶点的父亲。
(3)把A从open list中移除,加入到close list(封闭列表) 中,close list中的每个顶点都是现在不需要再关注的。
(4)检查所有与它相邻的顶点,忽略其中在close list中或是不可走的顶点,如果顶点不在open lsit中,则把它们加入到open list中。把我们选定的顶点设置为这些新加入的顶点的父亲。
(5)如果某个相邻的顶点已经在open list中,则检查这条路径是否更优,也就是说经由当前顶点到达那个顶点是否具有更小的 G 值。如果没有,不做任何操作。反之,如果 G 值更小,则把那个顶点的父亲设为当前顶点 ,然后重新计算那个顶点的 F 值和 G 值。
(6)从open list中选择 F 值最小的顶点,把它从open list里取出,放到close list中。
(7)重复步骤4~6,直到把终点加入到了open list中,此时路径已经找到了,或者查找终点失败,并且open list是空的,此时没有路径。
(8)从终点开始,每个顶点沿着父顶点移动直至起点,这就是搜索到的路径。

应用

地铁线路图作为有向图的数据结构,在确定起点和终点顶点位置后,通过A*的实现思路,从起点出发寻找周围的有向连接顶点,把它们加入到open list中,然后选择 F 值最小的顶点,把它从open list里取出,放到close list中,继续寻找该顶点周围的有向连接顶点,反复进行搜索,直到找到目标顶点位置为止。


image.png

总结

A*算法能够快速找到较短路径,在较大地图中使用,遍历获取F值最小的顶点优化以后速度还能提升数倍;在游戏地图、路径搜索类应用中使用该算法较为常见,如果出现山地、河流等制约条件,无非就是在启发函数中增加这些条件作为权值来改变优先级,从而快速得到最佳选择。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350