C++A*算法并不总是在路径中具有目标节点
C++ A* algorithm not always having the target node in path
我在C++中实现了一个A*算法,但向量中并不总是有目标节点,这导致了一个无休止的循环。我正在使用的库是:https://nullptr.club/libkmint/index.html.函数shortestPathToDist((应该执行以下操作:使用A*查找从源节点到目标节点的最短路径并返回该路径。这是a*的正确实现吗?还是我做错了什么?
Helper.hpp:
#ifndef UFO_HELPER_HPP
#define UFO_HELPER_HPP
#include <map>
#include <iostream>
#include "kmint/map/map.hpp"
namespace kmint {
namespace ufo {
class helper {
public:
helper();
std::vector<const map::map_node*> shortestPathToDist(const kmint::map::map_node& source_node, const kmint::map::map_node& target_node);
private:
const map::map_node* helper::smallestDistance(std::map<const map::map_node*, float>& actualCost, std::map<const map::map_node*, float>& heuristicCost, std::vector<const kmint::map::map_node*>& queue);
float heuristic(const map::map_node& source_node, const map::map_node& target_node);
};
}
}
#endif
Helper.cpp:
#include "kmint/ufo/helper.hpp"
namespace kmint {
namespace ufo {
helper::helper() {
}
std::vector<const map::map_node*> helper::shortestPathToDist(const map::map_node& source_node, const map::map_node& target_node)
{
std::vector<const map::map_node*> path;
std::vector<const map::map_node*> visited;
std::vector<const map::map_node*> queue;
std::map<const map::map_node*, const map::map_node*> previous;
std::map<const map::map_node*, float> cost;
std::map<const map::map_node*, float> heuristic_cost;
queue.push_back(&source_node);
cost[&source_node] = 0;
heuristic_cost[&source_node] = heuristic(source_node, target_node);
while (queue.size() > 0) {
const map::map_node* shortest_path_node = smallestDistance(cost, heuristic_cost, queue);
for (int i = 0; i < shortest_path_node->num_edges(); i++) {
map::map_edge edge = (*shortest_path_node)[i];
const map::map_node *node_to = &edge.to();
if (std::find(visited.begin(), visited.end(), node_to) == visited.end()
&& std::find(queue.begin(), queue.end(), node_to) == queue.end()) {
queue.push_back(node_to);
}
if (cost.find(node_to) == cost.end() || cost[node_to] > cost[shortest_path_node] + edge.weight())
{
cost[node_to] = cost[shortest_path_node] + edge.weight();
heuristic_cost[node_to] = heuristic(*shortest_path_node, target_node);
previous[node_to] = shortest_path_node;
}
if (node_to->node_id() == target_node.node_id())
{
cost[node_to] = cost[shortest_path_node] + edge.weight();
heuristic_cost[node_to] = heuristic(*shortest_path_node, target_node);
previous[node_to] = shortest_path_node;
break;
}
}
queue.erase(queue.begin());
visited.push_back(shortest_path_node);
}
// shortest path to target_node
const map::map_node* current_node = nullptr;
for (auto const&[key, val] : previous) {
if (key != nullptr && key != NULL) {
if (key->node_id() == target_node.node_id()) {
current_node = val;
break;
}
}
}
path.clear();
if (current_node == nullptr || current_node == NULL) {
std::cout << "could not find target noden";
//this->shortest_path_to_target(source_node, target_node);
return path;
}
while (current_node != &source_node) {
if (current_node != nullptr && current_node != NULL) {
if (path.size() > 0) {
bool found = false;
for (auto &p : path) {
if (p != NULL && p != nullptr && p->node_id() == current_node->node_id()) {
found = true;
break;
}
}
if (!found) {
path.insert(path.begin(), current_node);
}
}
else {
path.insert(path.begin(), current_node);
}
}
for (auto const&[key, val] : previous) {
if (key != nullptr && key != NULL && current_node != nullptr && current_node != NULL) {
if (key->node_id() == current_node->node_id()) {
current_node = val;
break;
}
}
}
}
return path;
}
// manhatan heuristic
float helper::heuristic(const map::map_node& fNode, const map::map_node& sNode)
{
return std::abs(fNode.location().x() - sNode.location().x()) + std::abs(fNode.location().y() - sNode.location().y());
}
const map::map_node* helper::smallestDistance(std::map<const map::map_node*, float>& actualCost, std::map<const map::map_node*, float>& heuristicCost, std::vector<const map::map_node*>& queue)
{
const map::map_node* sDN = nullptr;
for (int i = 0; i < queue.size(); i++)
{
if (sDN == nullptr || actualCost[queue[i]] + heuristicCost[queue[i]] < actualCost[sDN] + heuristicCost[sDN]) {
sDN = queue[i];
}
}
return sDN;
}
}
}
queue.erase(queue.begin());
。这是一个bug。您正在擦除最旧的添加对象,而应该弹出当前最短路径节点。
您还应该从访问集中删除最短路径节点!
真正的问题是您没有使用正确的数据结构
std::vector<const map::map_node*> queue;
应该成为
using scored_node = std::pair<double, const map::map_node*>
std::priority_queue<scored_node, std::vector<scored_node>, std::greater<scored_node>> queue;
有了这个改变,你就不需要smallestDistance
了,你应该使用
const auto shortest_path_scored_node = queue.top();
const auto shortest_path_node = shortest_path_scored_node.second;
queue.pop();
visited.erase(shortest_path_node);
而不是使用矢量
std::vector<const map::map_node*> visited;
考虑到您只关心元素是否被访问,您应该使用无序集。您可以保证不费吹灰之力就能获得唯一性和快速检索。
std::unodered_set<const map::map_node*> visited;
相关文章:
- C++A*算法并不总是在路径中具有目标节点
- 使用 Dijkstra 算法跟踪两个节点之间的最短路径
- 如何仅在 2 个节点之间获取最短路径,给定邻接列表有向图?
- A*路径查找-如何有效地更新openNodes优先级队列中的节点值
- 计算路径根到节点的总和等于一定数字的数量
- 在由邻接列表表示的树中查找节点到另一个给定节点之间的路径
- 添加一个节点,并在通用树中的两个给定节点之间找到路径成本,其中c 中的儿童列表
- 查找树(不属于任何特定类型的简单连接树)中两个节点之间的路径
- 具有最大不同节点的根到叶路径
- 沿着路径查找节点数量
- 使用 Dijkstra 算法计算两个节点之间的最短路径
- 使用路径调查访问网格中的所有节点
- 使用 ros launch 创建一个目录,然后将其路径传递给不同的节点
- 打印与BST的直径相对应的节点所包含的路径
- 在二进制搜索树中显示到节点的路径
- 使用 BFS 查找 2 个节点之间的最短路径
- 找到最大路径总和,我们可以在二叉树中的任何节点开始和结束
- 如何在C++中将文件路径作为节点添加到树或堆栈中
- 用BFS算法求两节点间的最短路径
- 显示属于二叉搜索树深度路径的节点