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

C++ A*寻路和大量指针问题?,c++,path-finding,a-star,C++,Path Finding,A Star,我知道A*算法的实现问题在stackoverflow上比较常见(我已经看过很多其他帖子)。过去几天我一直在尝试实现一个简单的C++ A*系统。我只允许在四个方向上移动(没有对角线检查),所以这应该是一个特别简单的任务(这也是为什么我只有一个启发式作为我的成本)。此外,我已经逐步完成了代码,对于所有起始位置,对象都能够成功找到到目标的有效路径。然而,问题是我无法通过父指针后退一步并存储路径/移动序列。我使用的是引用,所以我不太清楚为什么指针赋值会有问题。我在一些简短的示例路径上浏览了我“认为”代码

我知道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);
}
//要访问优先级队列的底层容器,必须扩展功能
模板
S&Container(标准::优先级队列&q){
结构HackedQueue:private std::priority_队列{
静态S和容器(标准::优先级队列和q){
返回q.*&HackedQueue::c;
}
};
返回HackedQueue::Container(q);
}
//与“网格”的差异足以成为新对象
类型定义结构节点{
整数成本,posX,posY;
节点*父节点;
节点(int cost=0,int posX=0,int posY=0,Node*parent=0):成本(cost),posX(posX),posY(posY),parent(parent){}
//重载运算符将使cpp文件更易于读取
布尔运算符==(常量节点和rhs){
返回(posX==rhs.posX&&posY==rhs.posY);
}

bool操作符问题是您在
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;
struct status{};//表示位置,小于可比较的
结构节点{
地位;
成本g;
成本h;
父母地位;
成本分数()常量{return g+h;}
};
结构节点比较器{
布尔运算符(const node&x,const node&y)const{return x.score()
  • 插入:O(对数(n))
    • 插入节点以打开\u集
    • 插入返回的迭代器以打开\u映射
  • 查找最低分数节点:O(log(n))
    • 从open_集中弹出第一个节点
    • 从打开的地图中弹出相应的状态
  • 更新-如果邻居处于开放映射中,:O(日志(n))
    • 使用open_映射中的迭代器从open_集中弹出节点
    • 更新成本
    • 插入以打开集合
    • 更新open_映射以指向重新插入的迭代器

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

其他人已经提到了可能的问题,但我将更详细地解释

在堆栈上创建对象时(不使用“新建”)把它们放在容器中,你就是在创建你制作的原始对象的副本。因此,任何指向原始对象的指针都会一直指向在某个点被破坏的原始对象,而不会指向容器中的副本。此外,在容器中获取对象的地址并不是真正的节省,因为某些容器可能会移动在添加或删除元素时,将对象放置在周围

有两种方法可以解决这个问题

  • 不要使用指针,而是使用索引值,如向量中的位置或带有容器(如std::map)的某个键值
  • 使用new分配所有对象,并将指针存储在容器中。(可能会给内存管理带来一些麻烦。)

  • 顺便说一句,引用基本上都是指针,并且有相同的问题。

    我想知道有多少人会涉猎这些代码?我想我会发布它只是为了参考,但问题的实质是什么会导致父指针混乱。如果我在(300540)并且目标是(300570),我会添加四个节点:(300510),(270540),(330,540)和(300,570)。每个都将指向(300,540)。如果我所做的只是将它们设置为指向父级,为什么会出现此中断?这似乎是一项非常简单的任务。/我建议使用较短的路径(例如,长度2)进行调试。这样,您就可以花更少的时间逐步完成有效的代码,并且应该能够更轻松地解决问题。是的!谢谢您的帮助。我感觉自己像个大傻瓜。我想堆栈帧的重要性现在已经永久地根植在我的脑海中……我希望我能够接受多个答案。我最终以某种方式解决了这个问题什么非常规方式。不是动态分配所有内容,而是只动态分配每个parentNode。然后我传入该指针。我还将每个动态分配的parentNode存储在一个向量中。这将在命名空间执行结束时运行并释放。这是不可靠的,但没有内存泄漏。我将一定要运行并重写整个名称空间,但我确实很高兴它能工作。:)谢谢你的帮助
    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;