这种写法比较垃圾,表现在每次搜索一个点要遍历整个地图那么大的数组,如果地图为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. ReentrantLock(重入锁)简单源码分析

    1.ReentrantLock是基于AQS实现的一种重入锁. 2.先介绍下公平锁/非公平锁 公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁. 非公平锁 非公平锁是指多个线程获取锁的顺序并不是按照申 ...

  2. spring boot redis分布式锁 (转)

    一. Redis 分布式锁的实现以及存在的问题 锁是针对某个资源,保证其访问的互斥性,在实际使用当中,这个资源一般是一个字符串.使用 Redis 实现锁,主要是将资源放到 Redis 当中,利用其原子 ...

  3. 学习selendroid初衷

    为了解决工作中的一个问题,开始学习selendroid. 工作中,有一些所谓H5应用需要测试,这些应用程序描述如下: 通过微信平台传播,也就是依靠微信的朋友圈传播: 可以通过类似于http://XXX ...

  4. c++中class与struct的区别

    0. 结构是一种用关键字struct声明的自定义数据类型.与类相似,也可以包含构造函数,常数,字段,方法,属性,索引器,运算符和嵌套类型. 1.结构在堆栈中创建,是值类型,而类是引用类型.每当需要一种 ...

  5. 基于S3C2440的linux-3.6.6移植——LED驱动【转】

    本文转载自:http://www.voidcn.com/blog/lqxandroid2012/article/p-625005.html 目前的linux版本的许多驱动都是基于设备模型,LED也不例 ...

  6. HDU5015 233 Matrix —— 矩阵快速幂

    题目链接:https://vjudge.net/problem/HDU-5015 233 Matrix Time Limit: 10000/5000 MS (Java/Others)    Memor ...

  7. [转]text和content方法的区别

    r.text str #字符串方式的响应体,会自动根据响应头部的 字符编码进行解码 r.content bytes #字节方式的响应体,会自动为你解码 gzip 和 deflate 压缩 reques ...

  8. 程序员代码面试指南:IT名企算法与数据结构题目最优解

      第1章栈和队列 1设计一个有getMin功能的栈(士★☆☆☆) 1由两个栈组成的队列(尉★★☆☆) 5如何仅用递归函数和栈操作逆序一个栈(尉★★☆☆) 8猫狗队列(士★☆☆☆)10用一个栈实现另一 ...

  9. 树堆(Treap)

    平衡树 简介: 平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.平衡二叉树的常用实现方 ...

  10. tcpdump 探测器分析

    注:默认情况下,tcpdump临听它遇见的第一个网络接口,如果它选择了错误的接口,可以-i标志强行指定接口,如果DNS不能用,或者只是不希望tcpdump进行名字查找,请使用-n选项,这个选项(-n) ...