算法:Astar寻路算法改进,双向A*寻路算法

早前写了一篇关于A*算法的文章:《算法:Astar寻路算法改进

最近在写个js的UI框架,顺便实现了一个js版本的A*算法,与之前不同的是,该A*算法是个双向A*。

双向A*有什么好处呢?

我们知道,A*的时间复杂度是和节点数量以及起始点难度呈幂函数正相关的。

这个http://qiao.github.io/PathFinding.js/visual/该网址很好的演示了双向A*的效果,我们来看一看。

绿色表示起点,红色表示终点,灰色是墙面。稍浅的两种绿色分别代表open节点和close节点:

当路径通过狭窄通道时,如果起点离通道较近,则很容易找到了终点,把起点和终点交换一下,如图:

可以注意到,被查找的节点多了不止一倍。

我们可以认为,终点在狭窄地带是最差结果,在开阔地带是最优结果。再来看看双向A*算法的寻址:

可以看到,和单向的最优结果是很接近的。

观察浅绿色寻路节点我们可以注意到,当open节点第一次接触到之后,中止了查找。

根据该思路,实现算法如下:

        while (true) {
            minFNode = anra.AStarUtil.findMinNode(openList);
            openList.removeObject(minFNode);
            if (!closedList.contains(minFNode))
                closedList.push(minFNode);

            if (closedList.length > 500) {
                return;
            }
            if (minFNode == null || minFNode.equals(endNode))
                break;
            anra.AStarUtil.search(this, minFNode, openList, closedList, endNode);
            BIminFNode = anra.AStarUtil.findMinNode(BIopenList);
            BIopenList.removeObject(BIminFNode);
            if (!BIclosedList.contains(BIminFNode))
                BIclosedList.push(BIminFNode);

            if (BIclosedList.length > 500) {
                return;
            }
            if (BIminFNode == null || BIminFNode.equals(startNode))
                break;
            anra.AStarUtil.search(this, BIminFNode, BIopenList, BIclosedList, startNode);
            for (var i = 0; i < openList.length; i++) {
                for (var j = 0; j < BIopenList.length; j++) {
                    if (BIopenList[j].equals(openList[i])) {
                        BIminFNode = BIopenList[j];
                        minFNode = openList[i];
                        middleNode = minFNode;
                        break;
                    }
                }
                if (middleNode)
                    break;
            }
            if (middleNode)
                break;
        }
    findMinNode:function (openList) {
        if (openList.length == 0)
            return null;
        else if (openList.length == 1)
            return openList[0];
        openList.sort(function (a, b) {
            return a.f() - b.f();
        });
        return openList[0];
    },
    /*搜索*/
    search:function (router, node, openList, closedList, endNode) {
        var nodes = this.findAroundNode(router, node);
        if (nodes == null)
            return;
        for (var i = 0; i < 8; i++) {
            if (nodes[i] == null || nodes[i].level == null)continue;
            nodes[i].g = (i > 3 ? nodes[i].level[0]
                : nodes[i].level[1]) + node.g;
            nodes[i].h = this.caculateH(nodes[i], endNode);
            if (closedList.contains(nodes[i])) {
                continue;
            }
            if (!openList.contains(nodes[i])) {
                openList.push(nodes[i]);
                nodes[i].parent = node;
            } else {
                var idx = openList.indexOf(nodes[i]);
                var n = openList[idx];
                if (nodes[i].g < n.g) {
                    openList.remove(idx);
                    closedList.push(n);
                    nodes[i].parent = n.parent;
                    openList.splice(idx, 0, nodes[i]);
                }
            }
        }
    },
    /*查找指定节点周围的可用节点*/
    findAroundNode:function (router, node) {
        if (node == null)return null;
        var nodes = [];

        nodes[0] = ANodeFactory.create(router, node.i, node.j + 1);
        nodes[1] = ANodeFactory.create(router, node.i, node.j - 1);
        nodes[2] = ANodeFactory.create(router, node.i + 1, node.j);
        nodes[3] = ANodeFactory.create(router, node.i - 1, node.j);

        nodes[4] = ANodeFactory.create(router, node.i - 1, node.j + 1);
        nodes[5] = ANodeFactory.create(router, node.i + 1, node.j - 1);
        nodes[6] = ANodeFactory.create(router, node.i + 1, node.j + 1);
        nodes[7] = ANodeFactory.create(router, node.i - 1, node.j - 1);

        return nodes;
    },
    caculateH:function (p, endNode) {
        return (Math.abs(endNode.i - p.i) + Math.abs(endNode.j
            - p.j))
            * p.level[0];
    },
时间: 2024-10-12 23:12:26

算法:Astar寻路算法改进,双向A*寻路算法的相关文章

A*寻路算法的优化与改进

提要 通过对上一篇A*寻路算法的学习,我们对A*寻路应该有一定的了解了,但实际应用中,需要对算法进行一些改进和优化. Iterative Deepening Depth-first search- 迭代深化深度优先搜索 在深度优先搜索中一个比较坑爹情形就是在搜索树的一枝上没有要搜的结果,但是却非常深,甚至深不见底,这样就根本搜索不到结果.为了防止这种情况出现,就出现了Iterative Deepening的思想. 迭代深化搜索(Iterative deepening search, IDS)或者

opencv实现一种改进的Fast特征检测算法

引言 之前了解了Fast算法之后使用opencv自己实现了下,具体见http://www.cnblogs.com/Wiley-hiking/p/6898049.html.不过算法也有缺点,主要就是对边缘点和噪点的抗干扰能力不强.在<基于FAST改进的快速角点探测算法>文章中作者提出一种改进的Fast角点算法,提高算法的稳定性和抗干扰能力.自己读完后使用opencv实现了该算法,这里将学习过程进行一个记录. 1.原始Fast检测算法 有关原始Fast检测算法,自己写的小结在http://www.

K-means聚类算法的三种改进(K-means++,ISODATA,Kernel K-means)介绍与对比

  一.概述 在本篇文章中将对四种聚类算法(K-means,K-means++,ISODATA和Kernel K-means)进行详细介绍,并利用数据集来真实地反映这四种算法之间的区别. 首先需要明确的是上述四种算法都属于"硬聚类"算法,即数据集中每一个样本都是被100%确定得分到某一个类别中.与之相对的"软聚类"可以理解为每个样本是以一定的概率被分到某一个类别中. 先简要阐述下上述四种算法之间的关系,已经了解过经典K-means算法的读者应该会有所体会.没有了解过

[聚类算法]K-means优缺点及其改进

[聚类算法]K-means优缺点及其改进 [转]:http://blog.csdn.net/u010536377/article/details/50884416 K-means聚类小述 大家接触的第一个聚类方法,十有八九都是K-means聚类啦.该算法十分容易理解,也很容易实现.其实几乎所有的机器学习和数据挖掘算法都有其优点和缺点.那么K-means的缺点是什么呢? 总结为下: (1)对于离群点和孤立点敏感: (2)k值选择; (3)初始聚类中心的选择: (4)只能发现球状簇. 对于这4点呢的

「图形学」直线扫描——Bresenham算法改进了中点Bresenham算法?

前言 博主目前在学习<计算机图形学基础>这本书,使用的是第二版. 此书第五章开始讲解基本图形生成算法. 在5.1.3 Bresenham算法中,如是写到: 虽然中点Bresenham算法是一种效率非常高的算法,但也还有改进的余地. 而后,开始介绍Bresenham算法. 思考 然而通过学习和理解,博主发现这两种算法的原理完全相同: 每次在最大位移方向上走一步,而另一个方向上走步还是不走步取决于误差项的判别. 于是博主产生了疑问: Bresenham算法真的改进了中点Bresenham算法吗?

Step by Step 改进朴素贝叶斯算法

引言 如果你对naive bayes认识还处于初级阶段,只了解基本的原理和假设,还没有实现过产品级的代码,那么这篇文章能够帮助你一步步对原始的朴素贝叶斯算法进行改进.在这个过程中你将会看到朴素贝叶斯假设的一些不合理处以及局限性,从而了解为什么这些假设在简化你的算法的同时,使最终分类结果变得糟糕,并针对这些问题提出了改进的方法. 朴素贝叶斯(Naive Bayes) 出处: <机器学习>(Machine Learning by Tom M.Mitchell) 符号和术语 假设待分类的实例 X 可

排序算法系列:冒泡排序与双向冒泡排序

概述 排序算法应该算是一个比较热门的话题,在各个技术博客平台上也都有一些博文进行了一定程度的讲解.但还是希望能从自我完善的角度出发,可以更详细.全面.形象地表达这些算法的精髓.本文就先从最简单的冒泡排序开始说起,别说你已经彻底了解了冒泡排序算法(虽然一开始我也是这样以为的). 版权说明 本文链接:http://blog.csdn.net/lemon_tree12138/article/details/50474230 – Coding-Naga - 转载请注明出处 目录 概述 版权说明 目录 冒

改进的起泡排序算法--java

一.基本思路: 冒泡排序是一种简单的交换类排序.其基本思路是从头开始扫描待排序的元素,在扫描过程中依次对相邻元素进行比较,将关键字值大的元素后移.每经过一趟排序后,关键字值最大的元素将移到末尾,此时记下该元素的位置,下一趟排序只需要比较到此位置为止,直到所有元素都已有序排列. 一般地,对n个元素进行冒泡排序,总共需要进行n-1趟.第1趟需要比较n-1次,第2趟需要比较n-2次,......第i趟需要比较n-i次. 二.算法 2.1原始起泡排序算法 public static int[] bubb

Four modifications for the Raft consensus algorithmRaft一致性算法的四个改进译文

最近用业余时间对Four modifications for the Raft consensus algorithm论文进行了翻译,该论文从4个方面优化了Raft实现,对工程实现的借鉴意义如下: 1.Cluster initialization:可以解决多数派节点异常的情况下,集群始终不可用问题,让少数派集群恢复到正常服务的状态. 2.Universally Unique Database Identifier:可以在多raft组.multi raft.多数据中心场景下,避免由于运维人员操作错

从 NavMesh 网格寻路回归到 Grid 网格寻路。

上一个项目的寻路方案是客户端和服务器都采用了 NavMesh 作为解决方案,当时的那几篇文章(一,二,三)是很多网友留言和后台发消息询问最多的,看来这个方案有着广泛的需求.但因为是商业项目,我无法贴出代码,只能说明下我的大致思路,况且也有些悬而未决的不完美的地方,比如客户端和服务器数据准确度和精度的问题,但是考虑到项目类型和性价比,我们忽略了这个点. 从今年5月份开始为期一个月,我的主要工作是为新项目寻找一个新的寻路方案.新项目是一个 RTS 实时竞技游戏,寻路要求是:每个寻路单位之间的碰撞精确