最近看了一些和图形、算法可视化相关的文章和代码,挺有意思,因而本身也学着作了些东西。html
迷宫小时候玩过,但历来没琢磨过迷宫是怎么设计的,觉得就是有人慢慢画出来的。看过网上这篇文章后,才知道,原来还能够随机生成:git
Maze Generation - Visualizing Algorithmsgithub
本身找了些资料参考,试着实现了几种以后,才慢慢领会到其中的一些原理。算法
算法中讨论的迷宫知足一个条件:迷宫中任意两点间有且只有一条路径。数组
要随机生成知足这样条件的迷宫,看起来很复杂啊。可是换个思路以后,就发现问题没那么复杂了。app
“树”其实就知足这个条件:布局
因此,生成随机的迷宫的问题,就转化为生成随机的树的过程。进一步,能够拆分为如下过程:动画
迷宫生成的不一样算法,区别主要在两点:spa
深度优先算法,也叫递归回溯算法。它会一直向随机方向生长,直到没法生成的位置,向后回退一格,继续生长,直到全部网格被填充。设计
深度优先算法生成的迷宫,会有比较明显的长路径,这是由于树在一开始生成的时候,空间比较充裕,会有一些长的枝条产生。
Prim 算法不会一直沿着一条路径进行探索,而是不断尝试随机的生长点。因此 Prim 算法生成的迷宫,分叉会比较多:
综合以上两种算法,我既不但愿有过长的路径,也不但愿有太多的分叉,因此我采用的思路的尝试沿着一条路径延伸最多必定的长度,而后再随机选择生长点执行相同的过程。
下图是在 40*40 的迷宫网格,每条枝干最多生长15个网格的效果:
这是执行了一段时间以后,迷宫大部分区域已经走过:
这是最后的效果:
项目地址:luobotang/maze
在线DEMO:迷宫生成算法 - luobotang
上面例子中的迷宫生成算法过程,迷宫网格是经过 HTML 的 <table> 实现,相邻网格的连通效果,则是借助 CSS 的边框样式。
整个迷宫的全部网格由二维数组表示,每一个网格的状态包含是否被访问、与相邻网格的连通状况等。
算法的执行过程由定时器驱动,每次执行一步,从而有动画的效果。
与图相关的最短路径算法,在生活中应该是有着普遍的应用了吧,从一个位置到另外一个位置,借助已有的路网,计算最短的路径。固然,还会由于路况、临时障碍,以及用户的我的偏好而产生不一样结果。
对于“图”上,基本要素就是:
Dijkstra 算法是用于计算最短路径的比较著名的一种算法,早在1956年就发表了。
Dijkstra 算法若是看算法的详细执行过程,有点复杂,可是其基本思路在作过以后会发现,貌似很简单。
已肯定 A 到 B 的最短路径,B 与 C 相连,且 A 到 B 的距离加上 B 到 C 的距离,小于当前 A 到 C 的距离,那么 A 到 B 再到 C 就是 A 到 C 的最短路径。
如上图所示,最初从 A 来看,到 C 的最短路径是 A -> C,距离是 4。但继续探索到 B 后,发现 A -> B 加上 B -> C 距离只有 3,比 A -> C 的距离要小,因此 A 到 C 的最短路径更新为:A -> B -> C。
基本思路上面都介绍了,细节就是每次探索节点时,都选择当前未探索过的到源点距离最短的节点,这样能够源点到当前点的路径已是最短路径。
图的可视化比较复杂了,只是绘制出来其实不难,但要将节点、边进行合理布局就比较麻烦,是另外一个话题了。
我选择用 vis.js 提供的 Network 来绘制图形,而后经过逐步执行算法来更新图形。
这是初始状态:
执行过程当中,会记录节点是否被访问,以及当前的最短路径和对应的距离:
所有执行完成后,就获得了源点开始到图中全部节点的最短路径:
项目地址:luobotang/graph
DEMO:Dijkstra 算法 - luobotang
项目的 Github Pages 配置有点问题,只能下载到本地以后再打开页面了。
其实上面这些实现起来并无特别困难,有不少现成的资料和代码能够利用。可是无论什么饭,都得本身吃过、消化过才是本身的。因此,我把本身吸取的“养分”记录下来,若是你也有兴趣,不妨本身上手一试。
最后,感谢阅读!