算法: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];
    },

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM