这种写法比较垃圾,表现在每次搜索一个点要遍历整个地图那么大的数组,如果地图为256*256,每次搜索都要执行65535次,如果遍历多个点就是n*65535,速度上实在是太垃圾了

简单说下思路,以后补充算法

优化重点在在open表和close表的遍历上,这两个地方优化后,astar会大量提速

close只用来查询所以可以用hash这样就避免了遍历

open首先用来查询是否有相同的点如果有会比较替换F值,其次用来遍历查询最小点,如果用优先级队列加hash可以减少2次遍历,但是相同点替换F值和父节点就没办法了,只能遍历一次(但一般找到该找的点就可以break,不需要完整遍历)

如果用java,c#,由于有垃圾回收机制,为了避免产生过多垃圾降低垃圾回收压力,可以用空闲对象池来避免频繁创建节点,控制内存泄露

原作者是http://www.codefans.net的JAROD

之所以说这个A-star算法高效,是因为它的open-list和close-list使用的完全是静态数组,这样就极大地降低了入栈出栈的负担。这个代码非常值得推荐。

用法很简单:
route_pt[] result = null;
// result_pt是一个简单类,它只有两个成员变量:int x和int y。
// 参数说明:map是一个二维数组,具体见程序注释
AStarRoute2 asr = new AStarRoute2(map, start_x, start_y, end_x, end_y);
try {
    result = asr.getResult();
}catch (Exception ex) {
}
如果result != null那么寻路就成功了。
注意:最后获得的路径,是从终点指向起点的。您可以把两组参数倒过来传,以获得正常方向的返回值。

本人对JAROD的代码略作修改,主要是用循环取代了递归,避免栈溢出。
这是本人修改后的八方向寻路算法。如下:

import java.util.ArrayList;

public class AStarRoute2 {
    private int[][] map;  // 地图矩阵,0表示能通过,1表示不能通过
    private int map_w;    // 地图宽度
    private int map_h;    // 地图高度
    private int start_x;  // 起点坐标X
    private int start_y;  // 起点坐标Y
    private int goal_x;   // 终点坐标X
    private int goal_y;   // 终点坐标Y

    private boolean closeList[][];            // 关闭列表
    public  int openList[][][];               // 打开列表
    private int openListLength;

    private static final int EXIST = 1;
    private static final int NOT_EXIST = 0;

    private static final int ISEXIST = 0;  
    private static final int EXPENSE = 1;     // 自身的代价
    private static final int DISTANCE = 2;    // 距离的代价
    private static final int COST = 3;        // 消耗的总代价
    private static final int FATHER_DIR = 4;  // 父节点的方向

    public static final int DIR_NULL = 0;
    public static final int DIR_DOWN = 1;     // 方向:下
    public static final int DIR_UP = 2;       // 方向:上
    public static final int DIR_LEFT = 3;     // 方向:左
    public static final int DIR_RIGHT = 4;    // 方向:右
    public static final int DIR_UP_LEFT = 5;
    public static final int DIR_UP_RIGHT = 6;
    public static final int DIR_DOWN_LEFT = 7;
    public static final int DIR_DOWN_RIGHT = 8;

    private int astar_counter;                // 算法嵌套深度
    private boolean isFound;                  // 是否找到路径

    public AStarRoute2(int[][] mx, int sx, int sy, int gx, int gy){
        start_x = sx;
        start_y = sy;
        goal_x  = gx;
        goal_y  = gy;
        map     = mx;
        map_w   = mx.length;
        map_h   = mx[0].length;
        astar_counter = 5000;
        initCloseList();
        initOpenList(goal_x, goal_y);
    }

    // 得到地图上这一点的消耗值
    private int getMapExpense(int x, int y, int dir)
    {
        if(dir < 5){
            return 10;
        }else{
            return 14;
        }
    }

    // 得到距离的消耗值
    private int getDistance(int x, int y, int ex, int ey)
    {
        return 10 * (Math.abs(x - ex) + Math.abs(y - ey));
    }

    // 得到给定坐标格子此时的总消耗值
    private int getCost(int x, int y)
    {
        return openList[x][y][COST];
    }

    // 开始寻路
    public void searchPath()
    {
        addOpenList(start_x, start_y);
        aStar(start_x, start_y);
    }

    // 寻路
    private void aStar(int x, int y)
    {
        // 控制算法深度
        for(int t = 0; t < astar_counter; t++){
            if(((x == goal_x) && (y == goal_y))){
                isFound = true;
                return;
            }
            else if((openListLength == 0)){
                isFound = false;
                return;
            }

            removeOpenList(x, y);
            addCloseList(x, y);

            // 该点周围能够行走的点
            addNewOpenList(x, y, x, y + 1, DIR_UP);
            addNewOpenList(x, y, x, y - 1, DIR_DOWN);
            addNewOpenList(x, y, x - 1, y, DIR_RIGHT);
            addNewOpenList(x, y, x + 1, y, DIR_LEFT);
            addNewOpenList(x, y, x + 1, y + 1, DIR_UP_LEFT);
            addNewOpenList(x, y, x - 1, y + 1, DIR_UP_RIGHT);
            addNewOpenList(x, y, x + 1, y - 1, DIR_DOWN_LEFT);
            addNewOpenList(x, y, x - 1, y - 1, DIR_DOWN_RIGHT);

            // 找到估值最小的点,进行下一轮算法
            int cost = 0x7fffffff;
            for(int i = 0; i < map_w; i++){
                for(int j = 0; j < map_h; j++){
                    if(openList[i][j][ISEXIST] == EXIST){
                        if(cost > getCost(i, j)){
                            cost = getCost(i, j);
                            x = i;
                            y = j;
                        }
                    }
                }
            }
        }
        // 算法超深
        isFound = false;
        return;
    }

    // 添加一个新的节点
    private void addNewOpenList(int x, int y, int newX, int newY, int dir)
    {
        if(isCanPass(newX, newY)){
            if(openList[newX][newY][ISEXIST] == EXIST){
                if(openList[x][y][EXPENSE] + getMapExpense(newX, newY, dir) < 
                    openList[newX][newY][EXPENSE]){
                    setFatherDir(newX, newY, dir);
                    setCost(newX, newY, x, y, dir);
                }
            }else{
                addOpenList(newX, newY);
                setFatherDir(newX, newY, dir);
                setCost(newX, newY, x, y, dir);
            }
        }
    }

    // 设置消耗值
    private void setCost(int x, int y, int ex, int ey, int dir)
    {
        openList[x][y][EXPENSE] = openList[ex][ey][EXPENSE] + getMapExpense(x, y, dir);
        openList[x][y][DISTANCE] = getDistance(x, y, ex, ey);
        openList[x][y][COST] = openList[x][y][EXPENSE] + openList[x][y][DISTANCE];
    }

    // 设置父节点方向
    private void setFatherDir(int x, int y, int dir)
    {
        openList[x][y][FATHER_DIR] = dir;
    }

    // 判断一个点是否可以通过
    private boolean isCanPass(int x, int y)
    {
        // 超出边界
        if(x < 0 || x >= map_w || y < 0 || y >= map_h){
            return false;
        }
        // 地图不通
        if(map[x][y] != 0){
            return false;
        }
        // 在关闭列表中
        if(isInCloseList(x, y)){
            return false;
        }
        return true;
    }

    // 移除打开列表的一个元素
    private void removeOpenList(int x, int y)
    {
        if(openList[x][y][ISEXIST] == EXIST){
            openList[x][y][ISEXIST] = NOT_EXIST;
            openListLength--;
        }
    }

    // 判断一点是否在关闭列表中
    private boolean isInCloseList(int x, int y)
    {
        return closeList[x][y];
    }

    // 添加关闭列表
    private void addCloseList(int x, int y)
    {
        closeList[x][y] = true;
    }

    // 添加打开列表
    private void addOpenList(int x, int y)
    {
        if(openList[x][y][ISEXIST] == NOT_EXIST){
            openList[x][y][ISEXIST] = EXIST;
            openListLength++;
        }
    }

    // 初始化关闭列表
    private void initCloseList()
    {
        closeList = new boolean[map_w][map_h];
        for(int i = 0; i < map_w; i++){
            for(int j = 0; j < map_h; j++){
                closeList[i][j] = false;
            }
        }
    }

    // 初始化打开列表
    private void initOpenList(int ex, int ey)
    {
        openList  = new int[map_w][map_h][5];
        for(int i = 0; i < map_w; i++){
            for(int j = 0; j < map_h; j++){
                openList[i][j][ISEXIST] = NOT_EXIST;
                openList[i][j][EXPENSE] = getMapExpense(i, j, DIR_NULL);
                openList[i][j][DISTANCE] = getDistance(i, j, ex, ey);
                openList[i][j][COST] = openList[i][j][EXPENSE] + openList[i][j][DISTANCE];
                openList[i][j][FATHER_DIR] = DIR_NULL;
            }
        }
        openListLength = 0;
    }

    // 获得寻路结果
    public route_pt[] getResult(){
        route_pt[] result;
        ArrayList<route_pt> route;
        searchPath();
        if(! isFound){
            return null;
        }
        route = new ArrayList<route_pt>();
        // openList是从目标点向起始点倒推的。
        int iX = goal_x;
        int iY = goal_y;
        while((iX != start_x || iY != start_y)){
            route.add(new route_pt(iX, iY));
            switch(openList[iX][iY][FATHER_DIR]){
            case DIR_DOWN:          iY++;            break;
            case DIR_UP:            iY--;            break;
            case DIR_LEFT:          iX--;            break;
            case DIR_RIGHT:         iX++;            break;
            case DIR_UP_LEFT:       iX--;   iY--;    break;
            case DIR_UP_RIGHT:      iX++;   iY--;    break;
            case DIR_DOWN_LEFT:     iX--;   iY++;    break;
            case DIR_DOWN_RIGHT:    iX++;   iY++;    break;
            }
        }
        int size = route.size();
        result = new route_pt[size];
        for(int i = 0; i < size; i++){
            result[i] = new route_pt((route_pt)route.get(i));
        }
        return result;
    }
}

一个高效的A-star寻路算法(八方向)(的更多相关文章

  1. 如何在Cocos2D游戏中实现A*寻路算法(八)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流 ...

  2. 寻路算法A*, JPS(跳点搜索)的一些杂谈

    A*是一个比较经典的启发式寻路算法.是基于dijkstra算法,但是加入了启发函数,使路径搜索效率更高.实现起来很简单.不过要做到通用性高,比如支持各种不同类型的地图,甚至不仅仅是地图,而是个图结构如 ...

  3. 一种高效的寻路算法 - B*寻路算法

    在此把这个算法称作B* 寻路算法(Branch Star 分支寻路算法,且与A*对应),本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍. 通过引入该 ...

  4. 【转载】 A* 寻路算法 (个人认为最详细,最通俗易懂的一个版本)

    原文地址: http://www.cppblog.com/christanxw/archive/2006/04/07/5126.html =============================== ...

  5. A*(也叫A star, A星)寻路算法Java版

    寻路算法有非常多种,A*寻路算法被公觉得最好的寻路算法. 首先要理解什么是A*寻路算法,能够參考这三篇文章: http://www.gamedev.net/page/resources/_/techn ...

  6. A*寻路算法的探寻与改良(三)

    A*寻路算法的探寻与改良(三) by:田宇轩                                        第三分:这部分内容基于树.查找算法等对A*算法的执行效率进行了改良,想了解细 ...

  7. 游戏AI之A*寻路算法(3)

    前言:寻路是游戏比较重要的一个组成部分.因为不仅AI还有很多地方(例如RTS游戏里操控人物点到地图某个点,然后人物自动寻路走过去)都需要用到自动寻路的功能. 本文将介绍一个经常被使用且效率理想的寻路方 ...

  8. 基于Unity的A星寻路算法(绝对简单完整版本)

    前言 在上一篇文章,介绍了网格地图的实现方式,基于该文章,我们来实现一个A星寻路的算法,最终实现的效果为: 项目源码已上传Github:AStarNavigate 在阅读本篇文章,如果你对于里面提到的 ...

  9. 三角网格上的寻路算法Part.2—A*算法

    背景 继上一篇三角网格Dijkstra寻路算法之后,本篇将继续介绍一种更加智能,更具效率的寻路算法-A*算法,本文将首先介绍该算法的思想原理,再通过对比来说明二者之间的相同与不同之处,然后采用类似Di ...

随机推荐

  1. CentOS 安装和配置 Mantis

    Mantis是一个基于PHP技术的轻量级的开源缺陷跟踪系统,以Web操作的形式提供项目管理及缺陷跟踪服务.在功能上.实用性上足以满足中小型项目的管理及跟踪.更重要的是其开源,不需要负担任何费用. 1. ...

  2. PHP收邮件receiveMail

    用PHP来发邮件,相信大家都不陌生,但读取收件箱的话,接触就少了,这次总结下自己的经验,希望能够帮助大家. 注意:1.PHP读取收件箱主要是利用imap扩展,所以在使用下面方法前,必须开启imap扩展 ...

  3. photoswipe 实现图片的单击放大

    1.项目结构 2.HTML 代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind=&qu ...

  4. javascript Date对象的介绍及linux时间戳如何在javascript中转化成标准时间格式

    1.Date对象介绍 Date对象具有多种构造函数.new Date()new Date(milliseconds)new Date(datestring)new Date(year, month)n ...

  5. Tomcat Session Clustering

    搭建 Tomcat 集群需要解决很多的问题,其中之一就是要解决 Session 共享问题.小规模集群可以使用 Tomcat 提供的 Session Clustering 来解决. For the im ...

  6. android系统启动框架、Activity界面显示过程详解

    一.Android系统框架 android的系统架构和其操作系统一样,采用了分层的架构.从架构图看,android分为四个层,从高层到低层分别是应用程序层.应用程序框架层.系统运行库层和linux核心 ...

  7. 2U网络机箱的尺寸是多少,4U网络机箱的尺寸是多少

    厚度以4.445cm为基本单位.1U就是4.445cm,2U则是1U的2倍为8.89cm.48.26cm=19英寸,如果是标准的机架式设备,宽应该是满足这个标准的.纵深的话 有600mm或者800mm ...

  8. html5--3.17 新增的表单重写

    html5--3.17 新增的表单重写 学习要点 对form元素的属性做一个小结,对个别属性进行一点补充 重点掌握新增的表单重写 form元素的属性小结 action/method/enctype/n ...

  9. C语言 写的 表达式求值。

    有不对的地方还望指出来,让我改正.谢谢.存一个代码 #include<stdio.h> #include<stdlib.h> #include<string.h> ...

  10. LuoguP4861 按钮

    传送门 这题一眼看上去要解\(k^x \equiv 1(mod\ m)\)的最小正整数解. 于是我打了一个扩展BSGS 这题这样做算的答案一直是0的.不过有另一个定理欧拉定理,\(k^{\varphi ...