A星尋徑算法

import java.util.Comparator;

// 節(jié)點(diǎn)類(lèi)
public class Node implements Comparable<Node>, Comparator<Node> {
    /**
     * 節(jié)點(diǎn)坐標(biāo)
     */
    public int x, y;
    /**
     * F(n)=G(n)+H(n)
     */
    public int f;
    /**
     * 起點(diǎn)到當(dāng)前點(diǎn)的移動(dòng)耗費(fèi)
     */
    public int g;
    /**
     * 當(dāng)前點(diǎn)到終點(diǎn)的移動(dòng)耗費(fèi),即
     * 曼哈頓距離|x1-x2|*水平方向單元格寬度+
     * |y1-y2|*垂直方向單元格寬度(忽略障礙物)
     */
    public int h;
    /**
     * 父節(jié)點(diǎn)
     */
    public Node parent;

    /**
     * 通過(guò)給定值構(gòu)造一個(gè)節(jié)點(diǎn)對(duì)象
     */
    public Node(int x, int y, Node parent) {
        this.x = x;
        this.y = y;
        this.parent = parent;
    }

    /**
     * 通過(guò)給定節(jié)點(diǎn)構(gòu)造一個(gè)新的節(jié)點(diǎn)對(duì)象
     */
    public Node(Node node) {
        x = node.x;
        y = node.y;
        f = node.f;
        g = node.g;
        h = node.h;
        parent = node.parent;
    }

    /**
     * 將節(jié)點(diǎn)重新賦值
     */
    public void reset(Node node) {
        x = node.x;
        y = node.y;
        f = node.f;
        g = node.g;
        h = node.h;
        parent = node.parent;
    }

    @Override
    public int compareTo(Node node) {
        if (f > node.f) return 1;
        else if (f < node.f) return -1;
        else return 0;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;
        if (!(obj instanceof Node)) return false;
        Node other = (Node) obj;
        if (x != other.x) return false;
        if (y != other.y) return false;
        return true;
    }

    @Override
    public int hashCode() {
        int prime = 31;
        int result = 1;
        result = prime * result + x;
        result = prime * result + y;
        return result;
    }

    @Override
    public String toString() {
        return "(" + x + "," + y + ") F=" + f + "";
    }

    @Override
    public int compare(Node node, Node other) {
        if (node.f > other.f) return 1;
        else if (node.f < other.f) return -1;
        else return 0;
    }

}



import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * A星算法步驟:
 * 1.起點(diǎn)先添加到開(kāi)啟列表中
 * 2.開(kāi)啟列表中有節(jié)點(diǎn)的話恢准,取出第一個(gè)節(jié)點(diǎn)魂挂,即最小F值的節(jié)點(diǎn),
 * ->判斷此節(jié)點(diǎn)是否是目標(biāo)點(diǎn),是則找到了馁筐,跳出;
 * ->根據(jù)此節(jié)點(diǎn)取得八個(gè)方向的節(jié)點(diǎn)涂召,求出G,H敏沉,F(xiàn)值果正;
 * ->判斷每個(gè)節(jié)點(diǎn)在地圖中是否能通過(guò)炎码,不能通過(guò)則加入關(guān)閉列表中,跳出;
 * ->判斷每個(gè)節(jié)點(diǎn)是否在關(guān)閉列表中秋泳,在則跳出辅肾;
 * ->判斷每個(gè)節(jié)點(diǎn)是否在開(kāi)啟列表中,在則更新G值轮锥,F(xiàn)值矫钓,還更新其父節(jié)點(diǎn);不在則將其添加到開(kāi)啟列表中舍杜,計(jì)算G值新娜,H值,F(xiàn)值既绩,添加其節(jié)點(diǎn)概龄。
 * 3.把此節(jié)點(diǎn)從開(kāi)啟列表中刪除,再添加到關(guān)閉列表中饲握;
 * 4.把開(kāi)啟列表中按照F值最小的節(jié)點(diǎn)進(jìn)行排序私杜,最小的F值在第一個(gè);
 * 5.重復(fù)2救欧,3衰粹,4步驟,直到目標(biāo)點(diǎn)在開(kāi)啟列表中笆怠,即找到了铝耻;目標(biāo)點(diǎn)不在開(kāi)啟列表中,開(kāi)啟列表為空蹬刷,即沒(méi)找到
 */
public class AStar {
    /**
     * 地圖數(shù)組
     */
    private int[][] map;
    /**
     * 障礙物數(shù)組
     */
    private int[] limit;
    /**
     * 不可達(dá)區(qū)域數(shù)組
     */
    private boolean[][] close;
    /**
     * 存放未關(guān)閉節(jié)點(diǎn)的集合
     */
    private List<Node> open;
    /**
     * 結(jié)果集
     */
    private List<Node> result;
    /**
     * 垂直或水平方向移動(dòng)的路徑評(píng)分
     */
    private final int COST_STRAIGHT = 64;
    /**
     * 斜方向移動(dòng)的路徑評(píng)分
     */
    private final int COST_DIAGONAL = 90;
    /**
     * 地圖數(shù)組的寬度
     */
    private int mapW;
    /**
     * 地圖數(shù)組的高度
     */
    private int mapH;
    /**
     * 是否能斜向移動(dòng)
     */
    public boolean isObliqueable;
    /**
     * 是否能直線移動(dòng)
     */
    public boolean isStraightable;
    /**
     * 起點(diǎn)節(jié)點(diǎn)對(duì)象
     */
    private Node startNode;
    /**
     * 當(dāng)前節(jié)點(diǎn)對(duì)象
     */
    private Node current;
    /**
     * 判斷通行的通用節(jié)點(diǎn)(另一個(gè)作用:Map所有key對(duì)應(yīng)的鍵 )
     */
    private Node tempNode;
    int count;

    /**
     * @param map   地圖數(shù)組
     * @param limit 不可通行區(qū)域編號(hào)的數(shù)組
     */
    public AStar(int[][] map, int... limit) {
        tempNode = new Node(0, 0, null);
        startNode = new Node(0, 0, null);
        open = new ArrayList<Node>();
        result = new ArrayList<Node>();
        isObliqueable = true;
        isStraightable = true;
        init(map, limit);
    }

    /**
     * 重新初始化 提高類(lèi)的復(fù)用性
     *
     * @param map   地圖數(shù)組
     * @param limit 不可通行區(qū)域編號(hào)的數(shù)組
     */
    public AStar init(int[][] map, int... limit) {
        this.map = map;
        this.limit = limit;
        if (close == null || mapW != map[0].length || mapH != map.length) {
            mapW = map[0].length;
            mapH = map.length;
            close = new boolean[mapH][mapW];
        }
        return this;
    }

    /**
     * 程序入口
     * 查找核心算法
     */
    public List<Node> searchPath(int startX, int startY,
                                 int targetX, int targetY) {
        if (startX < 0 || startX >= mapW || targetX < 0 || targetX >= mapW
                || startY < 0 || startY >= mapH || targetY < 0 || targetY >= mapH)
            return null;
        // 查找障礙集合是否存在下一步的坐標(biāo)
        for (int i = 0, y, x, h = close.length, w = close[0].length, len = limit.length; i < len; i++) {
            /** 將地圖數(shù)組映射到一個(gè)布爾二維數(shù)組(可通行為true其他為false) */
            for (y = 0; y < h; y++) {
                for (x = 0; x < w; x++) {
                    if (map[y][x] == limit[i]) {
                        close[y][x] = false;
                    } else {
                        close[y][x] = true;
                    }
                }
            }
        }
        count = 0;
        // 每次調(diào)用尋徑時(shí) 先清空所有集合中的原有數(shù)據(jù)
        open.clear();
        // 起點(diǎn)先添加到開(kāi)啟列表中
        startNode.x = startX;
        startNode.y = startY;
        open.add(startNode);
        while (!open.isEmpty()) {
            // 開(kāi)啟列表中排序瓢捉,把F值最低的放到最底端
            Collections.sort(open);
            // 從開(kāi)啟列表中取出并刪除第一個(gè)節(jié)點(diǎn)(F為最低的)
            current = open.remove(0);
            // 判斷是否找到目標(biāo)點(diǎn)
            if (current.x == targetX && current.y == targetY) {
                result.clear();
                // 將終點(diǎn)到起點(diǎn)的路徑添加到結(jié)果集中
                while (current.parent != null) {
                    result.add(current);
                    current = current.parent;
                }
                return result;
            }
            // 左
            if (isStraightable && current.x - 1 >= 0) {
                createNextStep(current.x - 1, current.y, targetX, targetY,
                        COST_STRAIGHT);
            }
            // 上
            if (isStraightable && current.y - 1 >= 0) {
                createNextStep(current.x, current.y - 1, targetX, targetY,
                        COST_STRAIGHT);
            }
            // 右
            if (isStraightable && current.x + 1 < mapW) {
                createNextStep(current.x + 1, current.y, targetX, targetY,
                        COST_STRAIGHT);
            }
            // 下
            if (isStraightable && current.y + 1 < mapH) {
                createNextStep(current.x, current.y + 1, targetX, targetY,
                        COST_STRAIGHT);
            }
            // 左上
            if (isObliqueable && current.x - 1 >= 0 && current.y - 1 >= 0) {
                createNextStep(current.x - 1, current.y - 1, targetX, targetY,
                        COST_DIAGONAL);
            }
            // 左下
            if (isObliqueable && current.x - 1 >= 0 && current.y + 1 < mapH) {
                createNextStep(current.x - 1, current.y + 1, targetX, targetY,
                        COST_DIAGONAL);
            }
            // 右上
            if (isObliqueable && current.x + 1 < mapW && current.y - 1 >= 0) {
                createNextStep(current.x + 1, current.y - 1, targetX, targetY,
                        COST_DIAGONAL);
            }
            // 右下
            if (isObliqueable && current.x + 1 < mapW && current.y + 1 < mapH) {
                createNextStep(current.x + 1, current.y + 1, targetX, targetY,
                        COST_DIAGONAL);
            }
            // 添加到關(guān)閉列表中
            close[current.y][current.x] = false;
        }
        return null;
    }

    /**
     * 根據(jù)坐標(biāo)可否通行創(chuàng)建下一步
     */
    private boolean createNextStep(int x, int y,
                                   int targetX, int targetY, int cost) {
        // 查找關(guān)閉集合中是否存在下一步的坐標(biāo)
        if (!close[y][x]) return false;
        // 查找開(kāi)啟列表中是否存在
        tempNode.x = x;
        tempNode.y = y;
        int index = open.indexOf(tempNode);
        Node node;
        if (index != -1) {
            // G值是否更小,即是否更新G办成,F(xiàn)值
            if (current.g + cost < open.get(index).g) {
                // 計(jì)算G F值
                tempNode.g = current.g + cost;
                tempNode.h = 0;
                tempNode.f = tempNode.g + tempNode.h;
                tempNode.parent = current;
                node = new Node(tempNode);
                // 替換原有節(jié)點(diǎn)
                open.set(index, node);
                ++count;
            }
        } else {
            // 計(jì)算G H F值
            tempNode.g = current.g + cost;
            tempNode.h = ((tempNode.x > targetX ? tempNode.x - targetX : targetX
                    - tempNode.x) << 6)
                    + ((tempNode.y > targetY ? tempNode.y - targetY : targetY - tempNode.y) << 6);
            tempNode.f = tempNode.g + tempNode.h;
            tempNode.parent = current;
            // 添加到開(kāi)啟列表中
            node = new Node(tempNode);
            open.add(node);
            ++count;
        }
        return true;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末泡态,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子迂卢,更是在濱河造成了極大的恐慌某弦,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冷守,死亡現(xiàn)場(chǎng)離奇詭異刀崖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)拍摇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)亮钦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人充活,你說(shuō)我怎么就攤上這事蜂莉±ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵映穗,是天一觀的道長(zhǎng)窖张。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蚁滋,這世上最難降的妖魔是什么宿接? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮辕录,結(jié)果婚禮上睦霎,老公的妹妹穿的比我還像新娘。我一直安慰自己走诞,他們只是感情好副女,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著蚣旱,像睡著了一般碑幅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上塞绿,一...
    開(kāi)封第一講書(shū)人閱讀 51,287評(píng)論 1 301
  • 那天沟涨,我揣著相機(jī)與錄音,去河邊找鬼位隶。 笑死拷窜,一個(gè)胖子當(dāng)著我的面吹牛开皿,可吹牛的內(nèi)容都是我干的涧黄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赋荆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼笋妥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起窄潭,我...
    開(kāi)封第一講書(shū)人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤春宣,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后嫉你,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體月帝,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年幽污,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚷辅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡距误,死狀恐怖簸搞,靈堂內(nèi)的尸體忽然破棺而出扁位,到底是詐尸還是另有隱情,我是刑警寧澤趁俊,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布域仇,位于F島的核電站,受9級(jí)特大地震影響寺擂,放射性物質(zhì)發(fā)生泄漏暇务。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一怔软、第九天 我趴在偏房一處隱蔽的房頂上張望般卑。 院中可真熱鬧,春花似錦爽雄、人聲如沸蝠检。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)叹谁。三九已至,卻和暖如春乘盖,著一層夾襖步出監(jiān)牢的瞬間焰檩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工订框, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留析苫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓穿扳,卻偏偏與公主長(zhǎng)得像衩侥,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矛物,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容