gpt4 book ai didi

c++ - A* 寻路和大量指针问题?

转载 作者:太空狗 更新时间:2023-10-29 21:06:06 26 4
gpt4 key购买 nike

我知道 A* 算法实现问题在 stackoverflow 上比较常见(我看过很多其他帖子)。在过去的几天里,我一直在尝试实现一个简单的 C++ A* 系统。我只允许在四个方向上移动(没有对角线检查),所以这应该是一个特别简单的任务(这也是为什么我的成本只有启发式)。此外,我已经逐步完成代码,并且对于所有起始位置,对象都能够成功找到通往目标的有效路径。然而,问题是我无法通过父指针返回并存储路径/移动序列。我正在使用引用,所以我不太确定为什么指针分配存在问题。我通过一些简短的示例路径浏览了我“认为”代码在纸上所做的事情,但我不明白我做错了什么。循环遍历最终应该为 NULL 的父指针,无限打印目标的 posY。

这是我的头文件:

    //to access a priority queue's underlying container, you must extend functionality
template <class T, class S, class C>
S& Container(std::priority_queue<T, S, C>& q) {
struct HackedQueue : private std::priority_queue<T, S, C> {
static S& Container(std::priority_queue<T, S, C>& q) {
return q.*&HackedQueue::c;
}
};
return HackedQueue::Container(q);
}
//different enough from a "Grid" to be a new object
typedef struct Node{
int cost, posX, posY;
Node* parent;
Node(int cost = 0, int posX = 0, int posY = 0, Node* parent = 0) : cost(cost), posX(posX), posY(posY), parent(parent) {}
//overloading operators will make the cpp file easier to read
bool operator==(const Node& rhs){
return (posX == rhs.posX && posY == rhs.posY);
}
bool operator<(const Node& rhs){
return (posX == rhs.posX && posY == rhs.posY && cost < rhs.cost);
}
} Node;
typedef struct NodeCompare{
//compare n1 against a node n2
bool operator()(const Node& n1, const Node& n2){
//if n2 has a lower cost, it has a higher priority
return n2.cost < n1.cost;
}
} NodeCompare;
//a list is essentially a linked list, a vector is a robust array; if you do not need random access, lists are faster than vectors
//we need random access for the priority queue, because it will constantly be resorted
bool PathSearch(std::list<Node>& path, const World& World, const WorldObj& obj, const Node& target); //path is our output list
void NodeSuccessors(std::priority_queue<Node, std::vector<Node>, NodeCompare>& open, std::list<Node>& closed, Node& parentNode, const World& World, const Node& target);
int Heuristic(int posX, int posY, const Node& target);
}

然后,这是我的实现:

bool PathSearch(std::list<Node>& path, const World& World, const WorldObj& obj, const Node& target){
std::priority_queue<Node, std::vector<Node>, NodeCompare> open;
std::list<Node> closed;
//put our starting position into our queue of nodes to inspect
Node start(Heuristic(obj.GetposX(), obj.GetposY(), target), obj.GetposX(), obj.GetposY());
open.push(start);
while(!open.empty()){
Node bestNode = open.top(); //has the lowest score by definition
open.pop();
if(bestNode == target){ //made it to the target
Node* ptrNode = &bestNode;
while(ptrNode){ //this is where we would reconstruct the path
std::cout<<ptrNode->posY<<std::endl;
ptrNode = ptrNode->parent;
}
return 1;
}
NodeSuccessors(open, closed, bestNode, World, target); //look at the Node's neighbors
closed.push_back(bestNode);
}
return 0; //no path found
}
//check for towers and check for boundaries; if they exist, skip the creation of that node
//pathfinding works for up, down, left, right, but not diagonal movement
void NodeSuccessors(std::priority_queue<Node, std::vector<Node>, NodeCompare>& open, std::list<Node>& closed, Node& parentNode, const World& World, const Node& target){
std::vector<Node>& openVec = Container(open);
int offsetX, offsetY;
bool skip;
for(int i = 0; i < 4; ++i){
offsetX = 0; offsetY = 0;
skip = 0;
if(i == 0) offsetY = -30; //up
else if(i == 1) offsetY = 30; //down
else if(i == 2) offsetX = -30; //left
else if(i == 3) offsetX = 30; //right
//add check for out of boundaries or in an occupied space
Node newNode(parentNode.cost + Heuristic((parentNode.posX + offsetX), (parentNode.posY + offsetY), target), parentNode.posX + offsetX, parentNode.posY + offsetY, &parentNode);
//if the Node already exists on open or closed with a lower score, we can skip to the next neighbor
//if the Node already exists on open or closed with a higher score, then we need to remove it
//the erasing is somewhat expensive, but simplifies the implementation
for(std::list<Node>::iterator itr = closed.begin(); itr != closed.end(); ++itr){
if(*itr < newNode){
skip = 1;
break;
}
else if(*itr == newNode){
closed.erase(itr);
break;
}
}
if(skip) continue;
for(std::vector<Node>::iterator itr = openVec.begin(); itr != openVec.end(); ++itr){
if(*itr < newNode){
skip = 1;
break;
}
else if(*itr == newNode){
openVec.erase(itr);
break;
}
}
if(skip) continue;
open.push(newNode);
}
}
int Heuristic(int posX, int posY, const Node& target){
return abs(posX - target.posX) + abs(posY - target.posY);
}

通过检查,closed 和 open 包含正确的结果。所以,我确定我正在用我的指针做一些非常愚蠢的事情。任何帮助将不胜感激。 :)

最佳答案

问题是您在 PathSearch() 中在堆栈上创建了一个实例并将其地址传递给 NodeSuccessors()

这不完全是关于你的问题,而是你的算法有性能问题。优先级队列是一个很好的选择,因为优先级队列在查找得分最低的节点时的复杂度为 O(1),在插入节点时的复杂度为 O(log(n))。但是,您的算法在打开和关闭中查找节点的时间复杂度为 O(n)。如果您还保持节点的顺序以便您可以在 O(log(n)) 中找到一个节点,则性能会好得多。


我记不太清了,但这是我使用的一个简短结构。

struct status {}; // represents the position, less-than comparable

struct node {
status s;
cost g;
cost h;
status parent;

cost score() const { return g + h; }
};

struct node_comparator {
bool operator(const node& x, const node& y) const { return x.score() < y.score(); }
};

typedef std::multiset<node, node_comparator> open_set;
// should be multiset since two or more nodes can have the same score

typedef std::map<Status, typename open_set::iterator> open_map;
  • 插入:O(log(n))
    • 插入一个节点到open_set
    • 将返回的迭代器插入到open_map
  • 寻找得分最低的节点:O(log(n))
    • 从open_set中弹出第一个节点
    • 从open_map中弹出相应状态
  • 更新 - 如果邻居在 open_map 中,:O(log(n))
    • 使用 open_map 中的迭代器从 open_set 中弹出节点
    • 更新成本
    • 插入到open_set
    • 更新 open_map 以指向重新插入的迭代器

插入或删除时会动态分配大量元素。为容器采用池分配器可能会有所帮助。

关于c++ - A* 寻路和大量指针问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8276554/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com