赞
踩
目录
1.学习算法最重要的是理解算法的每一步,而不是记住算法。
2.建议读者学习算法的时候,自己手动一步一步地运行算法。
A*搜索算法(A-Star Search Algorithm)是一种启发式搜索算法,主要用于在图形或网络结构中寻找从起始节点到目标节点的最短路径。它结合了Dijkstra算法确定性的最优性(保证找到的是实际最短路径)和Best-First Search(最佳优先搜索)的高效性(通过启发式信息指导搜索方向),在保证找到最优解的同时尽可能减少搜索范围。
数据结构定义: 首先,我们需要定义一些数据结构来表示搜索空间中的节点。每个节点通常包含位置信息、从起始点到该节点的代价 g(n)
、估计到达目标点的成本 h(n)
以及父节点引用。
- typedef struct Node {
- int x, y; // 假设这是一个二维地图上的节点坐标
- double g; // 从起始节点到当前节点的实际代价
- double h; // 到达目标节点的启发式估计代价
- double f; // f(n) = g(n) + h(n),综合评估函数值
- struct Node* parent; // 指向父节点的指针,用于追踪路径
- } Node;
-
- // 可能还会有用于存储整个地图或开放列表和关闭列表的数据结构
初始化: 初始化起始节点,设置其 g
值为0,计算 h
值,并将起始节点添加到开放列表中。
- Node start;
- start.x = startX;
- start.y = startY;
- start.g = 0;
- start.h = heuristic(start, target); // 使用某种启发式函数计算初始h值
- start.f = start.g + start.h;
- pushToOpenList(&start);
启发式函数: 定义一个启发式函数,它提供了一种对从当前节点到目标节点距离的估算。例如,在网格环境中,可以使用曼哈顿距离或欧几里得距离作为启发式函数。
- double heuristic(Node current, Node goal) {
- return abs(current.x - goal.x) + abs(current.y - goal.y); // 曼哈顿距离
- // 或者
- return sqrt(pow((current.x - goal.x), 2) + pow((current.y - goal.y), 2)); // 欧几里得距离
- }
开放列表与关闭列表管理: 创建两个集合,一个是开放列表(Open List),存放待检查的节点;另一个是关闭列表(Closed List),存放已检查过的节点。
搜索循环: 在每一步迭代中,从开放列表中选择具有最小 f
值的节点(最优节点)。如果这个节点是目标节点,则搜索结束,开始回溯构建最终路径。否则,将当前节点移到关闭列表,并检查其所有邻居节点:
- while (!isEmpty(openList)) {
- Node* currentNode = findMinFInOpenList(openList); // 获取当前最优节点
- if (isSameNode(currentNode, &target)) { // 达到目标节点
- reconstructPath(currentNode); // 回溯路径
- break;
- }
-
- removeFromOpenList(openList, currentNode);
- addToClosedList(closedList, currentNode);
-
- for (each neighbor in currentNode's neighbors) {
- if (neighbor is not in closedList) {
- double tentative_g = currentNode->g + getCost(currentNode, neighbor);
- if (tentative_g < neighbor->g || neighbor not in openList) {
- neighbor->parent = currentNode;
- neighbor->g = tentative_g;
- neighbor->h = heuristic(neighbor, target);
- neighbor->f = neighbor->g + neighbor->h;
- if (neighbor not in openList) {
- pushToOpenList(neighbor);
- }
- }
- }
- }
- }
-
- // 清理并输出结果
路径回溯: 从目标节点开始,通过父节点引用一路回溯到起始节点,从而得到从起始到目标的最短路径。
- void reconstructPath(Node* node) {
- while (node != NULL) {
- // 将节点添加到路径列表或打印节点坐标
- node = node->parent;
- }
- }
请注意以上代码仅为概念性的伪代码片段,实际编写时需要根据具体问题填充缺失的细节,比如如何实现集合操作(如插入、删除、查找等)、如何处理连续空间中的邻接关系等。同时,为了提高效率,可能还需要引入优先队列来优化开放列表的操作,以保证每次都能直接获取当前最低f
值的节点。
最好情况:如果启发式函数是完美的,即对于每个节点,的值恰好等于从该节点到目标节点的实际最小代价,那么A*搜索将会模拟Dijkstra算法的行为,并且在找到解时达到最优。在这种情况下,最坏情况下的时间复杂度是 ,其中 表示图中边的数量,表示顶点数量。这是因为通常使用优先队列(如二叉堆)来保持开放列表,每次插入、删除和查找操作的时间复杂度为。
最坏情况:当启发式函数不是理想的低估函数时,A可能需要检查更多的节点才能找到解。此时时间复杂度难以精确估计,因为它依赖于启发式函数的质量以及图的具体结构。实际运行时可能会接近 ,其中 b
是平均 branching factor(每个节点的邻居数),d
是实际路径长度。在具有大量节点和边的图上,A的时间效率会显著降低,尤其是当启发式函数给出较差指引时。
总之,A*搜索算法的时间复杂度与启发式函数选择、图的结构和规模等因素密切相关,而空间复杂度则主要取决于需要记录的节点状态数量。良好的启发式函数能够有效引导搜索,从而在一定程度上降低时空复杂度。
最优性保证:
h(n)
是一致的(即对于任意节点n和其任何后继节点m,从起始节点到m的路径经过n时,h(n) <= h(m)
),并且是可接纳的(即它永远不会高估实际代价),A*可以确保找到从起始节点到目标节点的最短路径。效率高:
g(n)
和启发式估价 h(n)
的评估函数 f(n)
,A*能够优先考虑最有希望到达目标的节点,有效地减少了搜索空间。适应性强:
灵活性:
计算资源需求:
启发式函数的质量:
存储开销:
无法应对动态变化环境:
局部最优陷阱:
游戏开发:
机器人导航:
地图应用:
物流与配送优化:
图形用户界面(GUI)设计工具:
计算机视觉与图像处理:
人工智能和规划问题:
GIS地理信息系统:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。