[开发者心得] 算法学习与分享|经典寻路算法Dijkstra和A星算法

[复制链接]
2186 |0
季理GiLiGiLi 发表于 2023-7-14 23:22:47 | 显示全部楼层 |阅读模式
本帖最后由 季理GiLiGiLi 于 2023-11-13 15:33 编辑

最近,学习了一下寻路算法,就用我们编辑器写了一个demo,具体效果如下:
最佳路径图.gif
那就来简单说说两个算法吧~!

        Dijkstra算法就是通过在每一个地图格子中加入一个权值G,这个G值表示的是上一个格子到当前格子所需要花费的代价。Dijkstra在每次搜索的时候都会计算周围格子的G值,然后每次都选择G值最小的格子作为下一个拓展格子。搜索到最后,Dijkstra能返回代价最小的路径,也就是最优路径。而AStar算法 则相当于 Dijkstra算法 的扩展,它利用启发信息寻找最优路径。A* 算法需要在地图中搜索节点,并设定适合的启发函数进行指导。通过评价各个节点的代价值,获取下一需要拓展的最佳节点,直至到达最终目标点位置。A* 算法优点在于对环境反应迅速,搜索路径直接,是一种直接的搜索算法,因此被广泛应用于路径规划问题。其缺点是实时性差,每一节点计算量大、运算时间长,而且随着节点数的增多,算法搜索效率降低,而且A* 算法并没有完全遍历所有可行解,所得到的结果不一定是最优解。
        如果说,Dijkstra算法的权值函数是G,那么,A*算法的权值函数就是F=G+H,其中,H为一个启发函数。
        因为当A*算法启发函数值恒为0时,就相当于Dijkstra算法,故这里只贴A*算法代码。(已附完整项目)。



/**
* 算法思想:
  1. 把起点加入 open list 。

  2. 重复如下过程:

    a. 遍历open list ,查找F值最小的节点,把它作为当前要处理的节点,然后移到close list中

    b. 对当前方格的 8 个相邻方格一一进行检查,如果它是不可抵达的或者它在close list中,忽略它。否则,做如下操作:

        □  如果它不在open list中,把它加入open list,并且把当前方格设置为它的父亲

        □  如果它已经在open list中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更近。如果更近,把它的父亲设置为当前方格,并重新计算它的G和F值。
           如果你的open list是按F值排序的话,改变后你可能需要重新排序。

    c. 遇到下面情况停止搜索:

        □  把终点加入到了 open list 中,此时路径已经找到了,或者

        □  查找终点失败,并且open list 是空的,此时没有路径。

  3. 从终点开始,每个方格沿着父节点移动直至起点,形成路径。
*/




findPath(startPoint: Cell, endPoint: Cell) {
        //清除上一次算法留下的节点与节点之间的父子关系
        this.clearCellRelationship();

        //初始化开表和闭表
        let openList: Cell[] = [];     //待检查列表
        let closeList: Cell[] = [];    //closeList中的每个方格都是不需要再关注的。

        openList.push(startPoint);  //将起点加入openlist

        while (openList.length > 0) {

            //遍历open list ,查找F值最小的节点,把它作为当前要处理的节点,然后移到close list中
            let minPoint = this.findMinPoint(openList);
            let idx = openList.findIndex((p) => { return p.CellObj.guid == minPoint.CellObj.guid })
            openList.splice(idx, 1);
            closeList.push(minPoint);

            //寻找MinPoint周围的点(边界和障碍物不会算在内)
            let surroundPoints = this.findSurroundPoint(minPoint);
            surroundPoints.forEach((son) => {
                //如果SurroundPoints中的点在Close表中出现过,无视
                if (closeList.includes(son)) return;

                if (openList.includes(son)) {
                    let newPathG = this.calcG(son, minPoint);
                    if (newPathG < son.G) {
                        son.Parent = minPoint;
                        son.G = newPathG;
                        son.F = newPathG + son.F;
                    }
                } else {
                    //若该点没有在Open表中出现过,则直接计算F值存入点内,且将该点的父亲设置为minPoint
                    this.calcF(son, endPoint);
                    son.Parent = minPoint;
                    openList.push(son);
                }
            });

            //若已经到达终点,则退出循环
            if (openList.includes(endPoint)) {
                break;
            }
        }

        return this.getPathWay(endPoint);//返回寻路结果
    }



完整项目demo:
AStarAlgorithm.rar (110.14 KB, 下载次数: 102)
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表