C++ A* 算法:启发式路径搜索的黄金标准

目录

  • [C++ A* 算法:启发式路径搜索的黄金标准](#C++ A* 算法:启发式路径搜索的黄金标准)
    • 引言
    • [一、A* 算法核心原理](#一、A* 算法核心原理)
      • [1. 核心概念定义](#1. 核心概念定义)
      • [2. 启发函数(Heuristic Function)](#2. 启发函数(Heuristic Function))
    • [二、A* 算法 C++ 实现基础](#二、A* 算法 C++ 实现基础)
      • [1. 核心数据结构定义](#1. 核心数据结构定义)
      • [2. 辅助函数实现](#2. 辅助函数实现)
      • [3. A* 算法核心实现](#3. A* 算法核心实现)
    • [三、C++ 实战:A* 网格寻路完整代码](#三、C++ 实战:A* 网格寻路完整代码)
    • [四、A* 算法关键优化技巧](#四、A* 算法关键优化技巧)
      • [1. 启发函数优化](#1. 启发函数优化)
      • [2. 数据结构优化](#2. 数据结构优化)
      • [3. 搜索剪枝](#3. 搜索剪枝)
      • [4. 路径平滑](#4. 路径平滑)
    • 五、常见坑点与避坑指南
    • [六、A* vs 其他路径算法(核心差异)](#六、A* vs 其他路径算法(核心差异))
    • 七、总结

C++ A* 算法:启发式路径搜索的黄金标准

引言

A*(A-Star)算法是最经典的启发式路径搜索算法,结合了 Dijkstra 算法的"全局最优"和贪心算法的"启发式引导",在路径规划(如游戏寻路、机器人导航、地图导航)中应用广泛。A* 的核心是通过"预估代价 + 实际代价"的评估函数,优先搜索最有可能通向目标的路径,大幅减少无效搜索,效率远高于传统的 DFS/BFS/Dijkstra。本文将从核心原理、数据结构、实现框架到 C++ 实战(网格寻路),帮你彻底掌握 A* 算法。

一、A* 算法核心原理

1. 核心概念定义

在讲解算法前,先明确 A* 的关键术语(以网格寻路为例):

术语 含义 计算公式
g ( n ) g(n) g(n) 从起点到节点 n n n 的实际代价 如网格中相邻节点的移动成本(直走10,斜走14)
h ( n ) h(n) h(n) 从节点 n n n 到目标节点的预估代价(启发函数) 曼哈顿距离/欧几里得距离/切比雪夫距离
f ( n ) f(n) f(n) 节点 n n n 的总评估代价 f ( n ) = g ( n ) + h ( n ) f(n) = g(n) + h(n) f(n)=g(n)+h(n)
开放列表(Open List) 待探索的节点集合 优先队列(按 f ( n ) f(n) f(n) 升序)
关闭列表(Closed List) 已探索的节点集合 哈希表/二维数组(快速查询)

2. 启发函数(Heuristic Function)

启发函数是 A* 的灵魂,需满足 可采纳性 ( h ( n ) ≤ h(n) \leq h(n)≤ 实际代价),保证找到最优解:

  • 曼哈顿距离 (适合网格仅允许上下左右移动):
    h ( n ) = 10 × ( ∣ x n − x g o a l ∣ + ∣ y n − y g o a l ∣ ) h(n) = 10 \times (|x_n - x_{goal}| + |y_n - y_{goal}|) h(n)=10×(∣xn−xgoal∣+∣yn−ygoal∣)
  • 欧几里得距离 (适合网格允许任意方向移动):
    h ( n ) = 10 × ( x n − x g o a l ) 2 + ( y n − y g o a l ) 2 h(n) = 10 \times \sqrt{(x_n - x_{goal})^2 + (y_n - y_{goal})^2} h(n)=10×(xn−xgoal)2+(yn−ygoal)2
  • 切比雪夫距离 (适合网格允许斜向移动):
    h ( n ) = 10 × max ⁡ ( ∣ x n − x g o a l ∣ , ∣ y n − y g o a l ∣ ) h(n) = 10 \times \max(|x_n - x_{goal}|, |y_n - y_{goal}|) h(n)=10×max(∣xn−xgoal∣,∣yn−ygoal∣)

二、A* 算法 C++ 实现基础

1. 核心数据结构定义

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set>
#include <cmath>
#include <algorithm>
#include <climits>

using namespace std;

// ===================== 核心常量与类型定义 =====================
// 网格移动成本(直走10,斜走14,简化计算避免浮点数)
const int MOVE_STRAIGHT_COST = 10;
const int MOVE_DIAGONAL_COST = 14;

// 节点状态
struct Node {
    int x, y;          // 网格坐标
    int g_cost;        // 起点到当前节点的实际代价
    int h_cost;        // 到目标节点的预估代价
    int f_cost;        // 总代价 = g + h
    Node* parent;      // 父节点(用于回溯路径)
    bool is_obstacle;  // 是否是障碍物

    Node(int x_, int y_) : x(x_), y(y_), g_cost(INT_MAX), h_cost(0), 
                           f_cost(0), parent(nullptr), is_obstacle(false) {}

    // 计算总代价
    void calculate_f_cost() {
        f_cost = g_cost + h_cost;
    }
};

// 网格地图
using Grid = vector<vector<Node*>>;

// 优先队列的比较规则(f_cost 升序,f相同则h升序)
struct CompareNode {
    bool operator()(Node* a, Node* b) {
        if (a->f_cost != b->f_cost) {
            return a->f_cost > b->f_cost; // 小顶堆
        }
        return a->h_cost > b->h_cost;
    }
};

// 开放列表:优先队列(按f_cost排序)
using OpenList = priority_queue<Node*, vector<Node*>, CompareNode>;

// 关闭列表:哈希集合(快速查询)
using ClosedList = unordered_set<int>;

// 坐标哈希函数(用于ClosedList)
struct CoordHash {
    size_t operator()(const pair<int, int>& coord) const {
        return coord.first * 1000 + coord.second; // 假设网格大小不超过1000x1000
    }
};

2. 辅助函数实现

cpp 复制代码
// ===================== 辅助函数 =====================
// 计算曼哈顿距离(仅上下左右移动)
int calculate_manhattan_distance(Node* a, Node* b) {
    int dx = abs(a->x - b->x);
    int dy = abs(a->y - b->y);
    return MOVE_STRAIGHT_COST * (dx + dy);
}

// 计算切比雪夫距离(允许斜向移动)
int calculate_chebyshev_distance(Node* a, Node* b) {
    int dx = abs(a->x - b->x);
    int dy = abs(a->y - b->y);
    return MOVE_STRAIGHT_COST * max(dx, dy);
}

// 获取节点的哈希键(x*1000 + y)
int get_node_key(Node* node) {
    return node->x * 1000 + node->y;
}

// 获取相邻节点(8方向,可根据需求改为4方向)
vector<Node*> get_neighbors(Node* node, Grid& grid) {
    vector<Node*> neighbors;
    int rows = grid.size();
    if (rows == 0) return neighbors;
    int cols = grid[0].size();

    // 8个方向的偏移量
    vector<pair<int, int>> dirs = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1}, // 上下左右
        {-1, -1}, {-1, 1}, {1, -1}, {1, 1}  // 斜向
    };

    for (auto& dir : dirs) {
        int nx = node->x + dir.first;
        int ny = node->y + dir.second;
        // 检查坐标合法性
        if (nx >= 0 && nx < rows && ny >= 0 && ny < cols) {
            Node* neighbor = grid[nx][ny];
            // 跳过障碍物
            if (!neighbor->is_obstacle) {
                neighbors.push_back(neighbor);
            }
        }
    }

    return neighbors;
}

// 回溯路径(从目标节点到起点)
vector<pair<int, int>> reconstruct_path(Node* goal_node) {
    vector<pair<int, int>> path;
    Node* current = goal_node;

    // 从目标节点回溯到起点
    while (current != nullptr) {
        path.emplace_back(current->x, current->y);
        current = current->parent;
    }

    // 反转路径(起点→目标)
    reverse(path.begin(), path.end());
    return path;
}

// 初始化网格(创建节点,设置障碍物)
Grid init_grid(int rows, int cols, const vector<pair<int, int>>& obstacles) {
    Grid grid;
    for (int i = 0; i < rows; ++i) {
        vector<Node*> row;
        for (int j = 0; j < cols; ++j) {
            row.push_back(new Node(i, j));
        }
        grid.push_back(row);
    }

    // 设置障碍物
    for (auto& obs : obstacles) {
        int x = obs.first;
        int y = obs.second;
        if (x >= 0 && x < rows && y >= 0 && y < cols) {
            grid[x][y]->is_obstacle = true;
        }
    }

    return grid;
}

// 释放网格内存
void free_grid(Grid& grid) {
    for (auto& row : grid) {
        for (auto& node : row) {
            delete node;
        }
    }
    grid.clear();
}

// 打印路径
void print_path(const vector<pair<int, int>>& path) {
    if (path.empty()) {
        cout << "无可行路径!" << endl;
        return;
    }
    cout << "路径(共" << path.size() << "步):" << endl;
    for (int i = 0; i < path.size(); ++i) {
        cout << "(" << path[i].first << "," << path[i].second << ")";
        if (i != path.size() - 1) {
            cout << " → ";
        }
    }
    cout << endl;
}

// 打印网格(可视化路径和障碍物)
void print_grid(Grid& grid, const vector<pair<int, int>>& path) {
    int rows = grid.size();
    int cols = grid[0].size();

    // 将路径存入哈希集合,方便查询
    unordered_set<int, CoordHash> path_set;
    for (auto& p : path) {
        path_set.insert({p.first, p.second});
    }

    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            if (grid[i][j]->is_obstacle) {
                cout << "■ "; // 障碍物
            } else if (path_set.count({i, j})) {
                cout << "● "; // 路径
            } else {
                cout << "□ "; // 空网格
            }
        }
        cout << endl;
    }
}

3. A* 算法核心实现

cpp 复制代码
// ===================== A* 算法核心函数 =====================
vector<pair<int, int>> a_star_search(
    Grid& grid,
    pair<int, int> start_coord,
    pair<int, int> goal_coord,
    bool allow_diagonal = true // 是否允许斜向移动
) {
    // 1. 获取起点和目标节点
    Node* start_node = grid[start_coord.first][start_coord.second];
    Node* goal_node = grid[goal_coord.first][goal_coord.second];

    // 边界检查:起点/目标是障碍物
    if (start_node->is_obstacle || goal_node->is_obstacle) {
        cout << "起点或目标是障碍物!" << endl;
        return {};
    }

    // 2. 初始化开放列表和关闭列表
    OpenList open_list;
    ClosedList closed_list;

    // 3. 初始化起点
    start_node->g_cost = 0;
    if (allow_diagonal) {
        start_node->h_cost = calculate_chebyshev_distance(start_node, goal_node);
    } else {
        start_node->h_cost = calculate_manhattan_distance(start_node, goal_node);
    }
    start_node->calculate_f_cost();
    open_list.push(start_node);

    // 4. 核心搜索循环
    while (!open_list.empty()) {
        // 取出f_cost最小的节点
        Node* current_node = open_list.top();
        open_list.pop();

        // 如果是目标节点,回溯路径
        if (current_node == goal_node) {
            return reconstruct_path(goal_node);
        }

        // 将当前节点加入关闭列表
        closed_list.insert(get_node_key(current_node));

        // 遍历相邻节点
        vector<Node*> neighbors = get_neighbors(current_node, grid);
        for (Node* neighbor : neighbors) {
            // 跳过关闭列表中的节点
            if (closed_list.count(get_node_key(neighbor))) {
                continue;
            }

            // 计算从当前节点到相邻节点的代价
            int new_g_cost = current_node->g_cost;
            // 判断是否是斜向移动
            bool is_diagonal = (abs(current_node->x - neighbor->x) == 1) && 
                               (abs(current_node->y - neighbor->y) == 1);
            if (is_diagonal) {
                if (!allow_diagonal) continue; // 不允许斜向则跳过
                new_g_cost += MOVE_DIAGONAL_COST;
            } else {
                new_g_cost += MOVE_STRAIGHT_COST;
            }

            // 如果新路径更优,或节点不在开放列表中
            if (new_g_cost < neighbor->g_cost) {
                neighbor->parent = current_node;
                neighbor->g_cost = new_g_cost;
                // 更新h_cost
                if (allow_diagonal) {
                    neighbor->h_cost = calculate_chebyshev_distance(neighbor, goal_node);
                } else {
                    neighbor->h_cost = calculate_manhattan_distance(neighbor, goal_node);
                }
                neighbor->calculate_f_cost();

                // 如果节点不在开放列表中,加入
                // 注意:优先队列无法直接判断,这里简化处理(允许重复入队,关闭列表去重)
                open_list.push(neighbor);
            }
        }
    }

    // 开放列表为空,无路径
    return {};
}

三、C++ 实战:A* 网格寻路完整代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set>
#include <cmath>
#include <algorithm>
#include <climits>
#include <utility>

using namespace std;

// 核心常量
const int MOVE_STRAIGHT_COST = 10;
const int MOVE_DIAGONAL_COST = 14;

// 节点结构体
struct Node {
    int x, y;
    int g_cost;
    int h_cost;
    int f_cost;
    Node* parent;
    bool is_obstacle;

    Node(int x_, int y_) : x(x_), y(y_), g_cost(INT_MAX), h_cost(0), 
                           f_cost(0), parent(nullptr), is_obstacle(false) {}

    void calculate_f_cost() {
        f_cost = g_cost + h_cost;
    }
};

// 网格类型
using Grid = vector<vector<Node*>>;

// 优先队列比较规则
struct CompareNode {
    bool operator()(Node* a, Node* b) {
        if (a->f_cost != b->f_cost) {
            return a->f_cost > b->f_cost;
        }
        return a->h_cost > b->h_cost;
    }
};

// 开放列表和关闭列表
using OpenList = priority_queue<Node*, vector<Node*>, CompareNode>;
using ClosedList = unordered_set<int>;

// 辅助函数:计算曼哈顿距离
int calculate_manhattan_distance(Node* a, Node* b) {
    int dx = abs(a->x - b->x);
    int dy = abs(a->y - b->y);
    return MOVE_STRAIGHT_COST * (dx + dy);
}

// 辅助函数:计算切比雪夫距离
int calculate_chebyshev_distance(Node* a, Node* b) {
    int dx = abs(a->x - b->x);
    int dy = abs(a->y - b->y);
    return MOVE_STRAIGHT_COST * max(dx, dy);
}

// 辅助函数:获取节点哈希键
int get_node_key(Node* node) {
    return node->x * 1000 + node->y;
}

// 辅助函数:获取相邻节点
vector<Node*> get_neighbors(Node* node, Grid& grid) {
    vector<Node*> neighbors;
    int rows = grid.size();
    if (rows == 0) return neighbors;
    int cols = grid[0].size();

    vector<pair<int, int>> dirs = {
        {-1, 0}, {1, 0}, {0, -1}, {0, 1},
        {-1, -1}, {-1, 1}, {1, -1}, {1, 1}
    };

    for (auto& dir : dirs) {
        int nx = node->x + dir.first;
        int ny = node->y + dir.second;
        if (nx >= 0 && nx < rows && ny >= 0 && ny < cols) {
            Node* neighbor = grid[nx][ny];
            if (!neighbor->is_obstacle) {
                neighbors.push_back(neighbor);
            }
        }
    }

    return neighbors;
}

// 辅助函数:回溯路径
vector<pair<int, int>> reconstruct_path(Node* goal_node) {
    vector<pair<int, int>> path;
    Node* current = goal_node;
    while (current != nullptr) {
        path.emplace_back(current->x, current->y);
        current = current->parent;
    }
    reverse(path.begin(), path.end());
    return path;
}

// 辅助函数:初始化网格
Grid init_grid(int rows, int cols, const vector<pair<int, int>>& obstacles) {
    Grid grid;
    for (int i = 0; i < rows; ++i) {
        vector<Node*> row;
        for (int j = 0; j < cols; ++j) {
            row.push_back(new Node(i, j));
        }
        grid.push_back(row);
    }

    for (auto& obs : obstacles) {
        int x = obs.first;
        int y = obs.second;
        if (x >= 0 && x < rows && y >= 0 && y < cols) {
            grid[x][y]->is_obstacle = true;
        }
    }

    return grid;
}

// 辅助函数:释放网格内存
void free_grid(Grid& grid) {
    for (auto& row : grid) {
        for (auto& node : row) {
            delete node;
        }
    }
    grid.clear();
}

// 辅助函数:打印路径
void print_path(const vector<pair<int, int>>& path) {
    if (path.empty()) {
        cout << "无可行路径!" << endl;
        return;
    }
    cout << "\n最优路径(步数:" << path.size() << "):" << endl;
    for (int i = 0; i < path.size(); ++i) {
        cout << "(" << path[i].first << "," << path[i].second << ")";
        if (i != path.size() - 1) {
            cout << " → ";
        }
    }
    cout << endl;
}

// 辅助函数:打印网格
void print_grid(Grid& grid, const vector<pair<int, int>>& path) {
    int rows = grid.size();
    int cols = grid[0].size();

    unordered_set<int> path_set;
    for (auto& p : path) {
        path_set.insert(p.first * 1000 + p.second);
    }

    cout << "\n网格可视化(■=障碍物,●=路径,□=空):" << endl;
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            if (grid[i][j]->is_obstacle) {
                cout << "■ ";
            } else if (path_set.count(i * 1000 + j)) {
                cout << "● ";
            } else {
                cout << "□ ";
            }
        }
        cout << endl;
    }
}

// A* 核心搜索函数
vector<pair<int, int>> a_star_search(
    Grid& grid,
    pair<int, int> start_coord,
    pair<int, int> goal_coord,
    bool allow_diagonal = true
) {
    Node* start_node = grid[start_coord.first][start_coord.second];
    Node* goal_node = grid[goal_coord.first][goal_coord.second];

    if (start_node->is_obstacle || goal_node->is_obstacle) {
        cout << "错误:起点或目标是障碍物!" << endl;
        return {};
    }

    OpenList open_list;
    ClosedList closed_list;

    // 初始化起点
    start_node->g_cost = 0;
    if (allow_diagonal) {
        start_node->h_cost = calculate_chebyshev_distance(start_node, goal_node);
    } else {
        start_node->h_cost = calculate_manhattan_distance(start_node, goal_node);
    }
    start_node->calculate_f_cost();
    open_list.push(start_node);

    // 核心循环
    while (!open_list.empty()) {
        Node* current_node = open_list.top();
        open_list.pop();

        if (current_node == goal_node) {
            return reconstruct_path(goal_node);
        }

        closed_list.insert(get_node_key(current_node));

        vector<Node*> neighbors = get_neighbors(current_node, grid);
        for (Node* neighbor : neighbors) {
            if (closed_list.count(get_node_key(neighbor))) {
                continue;
            }

            int new_g_cost = current_node->g_cost;
            bool is_diagonal = (abs(current_node->x - neighbor->x) == 1) && 
                               (abs(current_node->y - neighbor->y) == 1);
            
            if (is_diagonal && !allow_diagonal) {
                continue;
            }

            new_g_cost += is_diagonal ? MOVE_DIAGONAL_COST : MOVE_STRAIGHT_COST;

            if (new_g_cost < neighbor->g_cost) {
                neighbor->parent = current_node;
                neighbor->g_cost = new_g_cost;
                
                if (allow_diagonal) {
                    neighbor->h_cost = calculate_chebyshev_distance(neighbor, goal_node);
                } else {
                    neighbor->h_cost = calculate_manhattan_distance(neighbor, goal_node);
                }
                neighbor->calculate_f_cost();

                open_list.push(neighbor);
            }
        }
    }

    return {};
}

// 主函数:测试A*算法
int main() {
    // 1. 配置网格(10x10)
    int rows = 10;
    int cols = 10;

    // 2. 设置障碍物
    vector<pair<int, int>> obstacles = {
        {2, 2}, {2, 3}, {2, 4}, {2, 5}, // 竖墙
        {5, 1}, {5, 2}, {5, 3}, {5, 4}, // 横墙
        {7, 6}, {7, 7}, {7, 8}           // 斜墙
    };

    // 3. 初始化网格
    Grid grid = init_grid(rows, cols, obstacles);

    // 4. 设置起点和目标
    pair<int, int> start = {0, 0};
    pair<int, int> goal = {9, 9};

    // 5. 执行A*搜索(允许斜向移动)
    vector<pair<int, int>> path = a_star_search(grid, start, goal, true);

    // 6. 打印结果
    print_path(path);
    print_grid(grid, path);

    // 7. 释放内存
    free_grid(grid);

    return 0;
}

四、A* 算法关键优化技巧

1. 启发函数优化

  • 可采纳性优先 :保证 h ( n ) ≤ h(n) \leq h(n)≤ 实际代价,确保最优解;
  • 动态加权 :搜索初期增大 h ( n ) h(n) h(n) 权重(如 f ( n ) = g ( n ) + 2 ∗ h ( n ) f(n) = g(n) + 2*h(n) f(n)=g(n)+2∗h(n)),加快搜索;后期恢复为 f ( n ) = g ( n ) + h ( n ) f(n) = g(n) + h(n) f(n)=g(n)+h(n),保证最优;
  • 预处理启发函数:如使用 Dijkstra 预计算所有节点到目标的距离(适用于静态地图)。

2. 数据结构优化

  • 开放列表优化 :使用 unordered_map 记录开放列表中的节点,避免重复入队(核心优化,减少无效计算);
  • 关闭列表优化 :用二维布尔数组替代哈希集合,查询效率从 O ( 1 ) O(1) O(1)(哈希)提升到 O ( 1 ) O(1) O(1)(数组,无哈希冲突);
  • 节点池化 :预先分配所有节点内存,避免频繁 new/delete

3. 搜索剪枝

  • 边界剪枝:跳过超出地图范围的节点;
  • 障碍物剪枝:直接跳过障碍物节点;
  • 方向剪枝:若不允许斜向移动,直接跳过斜向邻居。

4. 路径平滑

  • 移除冗余节点:如连续三个节点在同一直线上,可删除中间节点;
  • 折线优化:将"直角"路径优化为斜向路径(若允许)。

五、常见坑点与避坑指南

  1. 启发函数不可采纳

    • 坑: h ( n ) h(n) h(n) 大于实际代价,导致找到的路径不是最优解;
    • 避坑:优先使用曼哈顿/切比雪夫距离,确保 h ( n ) ≤ h(n) \leq h(n)≤ 实际代价。
  2. 开放列表重复入队

    • 坑:同一节点多次入队,导致优先队列膨胀,效率降低;
    • 避坑:用 unordered_map 记录开放列表中的节点,更新时直接修改优先级(或标记后跳过重复节点)。
  3. 坐标越界

    • 坑:访问网格时 x / y x/y x/y 超出范围,导致程序崩溃;
    • 避坑:获取邻居时严格检查坐标范围( n x ≥ 0 & & n x < r o w s & & n y ≥ 0 & & n y < c o l s nx \geq 0 \&\& nx < rows \&\& ny \geq 0 \&\& ny < cols nx≥0&&nx<rows&&ny≥0&&ny<cols)。
  4. 斜向移动代价错误

    • 坑:斜向移动代价与直走相同(如都为10),导致路径不合理;
    • 避坑:斜向代价设为 2 × \sqrt{2} \times 2 × 直走代价(如 14 ≈ 10×1.414)。
  5. 内存泄漏

    • 坑:未释放 Node 内存,导致内存泄漏;
    • 避坑:使用 free_grid 函数统一释放所有节点内存。

六、A* vs 其他路径算法(核心差异)

算法 核心特点 优势 劣势 适用场景
A* 启发式 f ( n ) = g + h f(n)=g+h f(n)=g+h 最优解+高效率 依赖高质量启发函数 静态地图路径规划
Dijkstra 仅用 g ( n ) g(n) g(n) 绝对最优解 效率低(遍历所有节点) 无启发信息的场景
BFS 等代价搜索 实现简单 仅适用于等代价网格,效率低 简单网格寻路
贪心算法 仅用 h ( n ) h(n) h(n) 搜索速度最快 无法保证最优解 对路径最优性要求低的场景

七、总结

核心要点回顾

  1. A 核心 *:通过 f ( n ) = g ( n ) + h ( n ) f(n) = g(n) + h(n) f(n)=g(n)+h(n) 评估节点优先级,结合全局最优( g ( n ) g(n) g(n))和启发引导( h ( n ) h(n) h(n));
  2. 核心组件
    • 开放列表:优先队列,按 f ( n ) f(n) f(n) 排序;
    • 关闭列表:记录已探索节点;
    • 启发函数:曼哈顿/切比雪夫距离(保证可采纳性);
  3. 关键优化
    • 数据结构:用数组替代哈希集合,避免重复入队;
    • 启发函数:保证可采纳性,动态加权提升效率;
    • 剪枝:跳过障碍物/越界节点;
  4. 核心优势:在保证最优解的前提下,搜索效率远高于 Dijkstra/BFS。

学习建议

  1. 先实现 4 方向网格寻路,理解核心流程;
  2. 扩展到 8 方向,掌握斜向移动的代价计算;
  3. 优化开放列表,解决重复入队问题;
  4. 将 A* 应用到实际场景(如游戏寻路、机器人导航)。

记住:A* 算法的本质是"有引导的全局搜索"------ g ( n ) g(n) g(n) 保证不遗漏最优解, h ( n ) h(n) h(n) 引导搜索方向,两者结合是路径规划的"黄金组合"。好的启发函数和数据结构优化,是 A* 高效运行的关键。

相关推荐
仰泳的熊猫2 小时前
题目2281:蓝桥杯2018年第九届真题-次数差
数据结构·c++·算法·蓝桥杯
2501_915918412 小时前
通过IPA 结构调整和资源指纹变化来处理 iOS 应用相似度问题
android·ios·小程序·https·uni-app·iphone·webview
blackicexs2 小时前
第九周第一天
数据结构·算法
实心儿儿2 小时前
C++ —— 多态
开发语言·c++
小小怪7502 小时前
C++中的代理模式高级应用
开发语言·c++·算法
Dfreedom.2 小时前
归一化技术全景指南
深度学习·算法·机器学习·归一化
Genevieve_xiao2 小时前
【写给新人】在 vscode 中配置适用于算法竞赛背景的 c/c++
c语言·vscode·算法
格林威2 小时前
工业相机图像高速存储(C++版):直接IO存储方法,附海康相机实战代码!
开发语言·c++·人工智能·数码相机·计算机视觉·视觉检测·工业相机
小此方3 小时前
Re:从零开始的 C++ STL篇(七)二叉搜索树增删查操作系统讲解(含代码)+key/key-value场景联合分析
开发语言·c++