A* 算法解决八数码问题交互演示

本文详述了使用A*算法解决八数码问题的JavaScript实现,包括算法思路、启发式搜索、优先队列的实现以及解决八数码问题的具体策略。通过交互式演示,读者可以更直观地理解A*算法。文中还讨论了如何计算节点大小、构建优先队列,并介绍了康托展开用于判断节点是否已访问的优化技巧。
摘要由CSDN通过智能技术生成

本文首发于我的个人博客网站:https://www.xerrors.fun/A-star-demo/
也可在此页面交互演示


1. A* 算法的 JavaScript 实现

Codepen 在线编辑上面的演示程序

A* 算法是一种启发式搜索算法,这篇文章介绍的算是挺容易理解的了,本篇文章侧重于实战部分,理论部分参考上面那篇文章。

由于是需要做出交互界面,所以需要使用 JavaScript 来实现 A* 算法,实现起来难度不是很大,不过很少使用 JavaScript 的数据处理,所以很多时候还是要一边查一边写。最终功夫不负有心人,熬出来了这个页面。

这里就体现出来使用 vuepress 作为博客网站框架的优点了,我可以在文章里面写 Vue,文档和交互式页面放在一起,可以更加直观的理解算法。

对广度优先搜索和深度优先搜索比较熟悉的同学,理解 A* 算法还有一个角度;深度优先和广度优点的区别在于分别是使用栈和队列来存储节点以及下一个节点的信息,从头部存取节点就是深度优点搜索,分别从头部和尾部存取节点就是广度优先搜索。

那么对于A*算法而言,不是使用栈或者队列,而是使用优先队列,也就是每一次取的节点是所有节点中的最小的。(这里的小的概念根据不同的用途有差异)。

这里说明一下,很多教程都是使用的 open 和 close 表,这里 duck 不必,使用优先队列就可以很好的解决问题。

首先思考两个问题:

  1. 如何计算每个节点的大小
  2. 如何实现优先队列

解决了上面两个问题之后,A* 算法的实现思路就跟 DFS 和 BFS 没什么区别了;

如何计算每个节点的大小?没错,就是使用A*算法的核心,启发式搜索,F = G + H,简单的再说一下,F 是该节点的大小,它取决于两个部分,G 表示已经付出的成本,也就是已经走了多少步;H 表示预计还要付出多少成本,也就是估计还要走多少步。

如何实现优先队列?实现优先队列的理想办法就是使用堆排序啦!但是呢,JavaScript 里面我没有找到现成的库(如果有的话可以在下方留言告诉我),而且我也懒得去自己实现,所以本篇文章的脚本并没有使用性能更好的堆排序,而是选择直接使用 JS 自带的排序。

2. 解决八数码问题

八数码问题,只要是看了上面的演示应该知道是什么。在实现的时候是使用一个节点类来表示的,关于 JavaScript 类不是很了解的同学可以了解一下JavaSript 类 - MDN。而且跟网上很多教程不一样的一个地方在于我把可移动的那个点作为 9,纯粹是为了看着舒服 😃 ,而且为了可视化方便,每个节点的历史足迹也都保存在了 chain 属性里面。

class Node {
   
  // 构造器
  constructor(path, pre_chain, to) {
   
    this.path = path; // 当前节点的路径
    this.index = path.indexOf(9); // 当前节点可移动的点的位置
    this.chain = Array.from(pre_chain)
    this.chain.push(this.calcId(path))
    this.to = to
  }
  ……
}

下面就是解决**如何计算每个节点的大小?**我所使用的是 距离 = 已走的步数 + 各个点距离终点的曼哈顿距离之和;关于计算曼哈顿距离需要稍微理解一下,因为这里计算曼哈顿距离是在二维上面计算曼哈顿距离,但是我的路径是一个一维的数组,所以需要把以为坐标转换到二维坐标来操作。核心在于 += 那一行。

启发式搜索所得到

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值