A星 最短路径搜索算法

10 篇文章 0 订阅
#include <iostream>
#include <vector>
#include <set>
#include <unordered_map>
#include <queue>
#include <tuple>
#include <cmath>

/*
 A  B      ·D
 E  F   G   H
 I  ·   K   L
 */

typedef int VertexID;
typedef std::tuple<double, double> Position;

struct VertexEdges
{
    Position pos;
    std::set<VertexID> edges;
};

std::unordered_map<VertexID, VertexEdges> mapEdges = {
    { 0 , {Position{0,0}, std::set<VertexID>{1,4}}}, // A
    { 1 , {Position{0,1}, std::set<VertexID>{0,5}}}, // B
    { 2 , {Position{0,2}, std::set<VertexID>{}}}, // C
    { 3 , {Position{0,3}, std::set<VertexID>{7}}}, // D
    { 4 , {Position{1,0}, std::set<VertexID>{0, 5, 8}}}, // E
    { 5 , {Position{1,1}, std::set<VertexID>{1, 4, 6}}}, // F
    { 6 , {Position{1,2}, std::set<VertexID>{5, 7, 10}}}, // G
    { 7 , {Position{1,3}, std::set<VertexID>{3, 6, 11}}}, // H
    { 8 , {Position{2,0}, std::set<VertexID>{4}}}, // I
    { 9 , {Position{2,1}, std::set<VertexID>{}}}, // J
    { 10, {Position{2,2}, std::set<VertexID>{6, 11}}}, // K
    { 11, {Position{2,3}, std::set<VertexID>{7, 10}}}, // L
};

struct PathNode
{
    VertexID pos;
    VertexID from;
    double sourceDistance = std::numeric_limits<double>::max();
    double estimateDistance = std::numeric_limits<double>::max();

    bool operator < (const PathNode& other) const noexcept
    {
        if (estimateDistance != other.estimateDistance) {
            return estimateDistance < other.estimateDistance;
        }
        else {
            return pos < other.pos;
        }
    }
};

double distance(const Position& pos1, const Position& pos2)
{
    auto& [x1, y1] = pos1;
    auto& [x2, y2] = pos2;
    double distance = std::sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2));
    return distance;
}


bool aStar(std::vector<PathNode>& pathReuslt,
    const std::unordered_map<VertexID, VertexEdges>& mapEdges,
    VertexID source,
    VertexID dest)
{
    const VertexEdges& destPos = mapEdges.at(dest);
    PathNode sourceNode = { source, source, 0, 0 };

    std::unordered_map<VertexID, PathNode> searchedNode;
    searchedNode.reserve(mapEdges.size());
    searchedNode[sourceNode.pos] = sourceNode;

    std::priority_queue<PathNode> openNodes;
    openNodes.push(sourceNode);

    while (openNodes.size() > 0) {
        PathNode currentNode = openNodes.top();
        openNodes.pop();

        const VertexEdges& currentPos = mapEdges.at(currentNode.pos);
        for (auto& neighbor : currentPos.edges) {
            const VertexEdges& neighborPos = mapEdges.at(neighbor);
            double edgeLength = distance(currentPos.pos, neighborPos.pos);
            double neighborDistance = currentNode.sourceDistance + edgeLength;
            auto& neighborNode = searchedNode[neighbor];

            if (neighborDistance < neighborNode.sourceDistance) {
                PathNode newDistanceNode;
                newDistanceNode.sourceDistance = neighborDistance;
                newDistanceNode.estimateDistance = neighborDistance + distance(currentPos.pos, destPos.pos);
                newDistanceNode.from = currentNode.pos;
                newDistanceNode.pos = neighbor;
                neighborNode = newDistanceNode;
                openNodes.push(newDistanceNode);

                if (neighbor == dest) {
                    pathReuslt.clear();
                    pathReuslt.push_back(searchedNode[dest]);
                    while (dest != source) {
                        dest = searchedNode[dest].from;
                        pathReuslt.push_back(searchedNode[dest]);
                    }
                    std::reverse(pathReuslt.begin(), pathReuslt.end());
                    return true;
                }
            }
        }
    }
    return false;
}

int main(int argc, const char* argv[]) {
    std::vector<PathNode> path;
    bool success = aStar(path, mapEdges, 0, 3);
    for (auto& node : path) {
        std::cout << node.pos << "\t";
    }
}

output:

0 1 5 6 7 3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值