我编写的代码试图解决传教士和食人族的问题,并已实施Node
以保存Node::arr
和Node::parent
中的信息。当函数bfs
返回时,这些将以最短的路径给出状态。
bfs
返回时,其parents
的数量正确。但是,当我在Visual Studio调试器中检查Node last
时,我注意到它的parents.arr
包含垃圾,即arr[0]=-858993460
。但是Node last
具有正确的arr
(问题的最终状态{0,0,1,3,3,0}
)。这些信息是如何丢失的?
node.h
#pragma once
#include <array>
class Node {
public:
std::array<int, 6> arr;
Node *parent;
Node(std::array<int, 6> arr, Node *parent = NULL);
Node();
};
node.cpp
#include "Node.h"
Node::Node(std::array<int, 6> arr, Node *parent) : arr(arr), parent(parent) {};
Node::Node(): parent(NULL) {};
的main.cpp
void applyMoves(queue<Node> &q, Node current_node, array<int, 3> moves) {
array<int, 6> arr = current_node.arr;
array<int, 3> left, right;
// apply valid moves to arr
// copy the arr to left and right and check if the move applied are valid
// if valid and no duplicates in the queue do proceed to the next lines below
Node n = Node(arr, ¤t_node);
q.push(n);
}
Node bfs(queue<Node> &q, array<array<int, 3>, 5> moves) {
while (!q.empty()) {
Node current = q.front();
q.pop();
if (achievedGoal(current.arr) == 1) {
return current;
}
for (const auto& move : moves) {
applyMoves(q, current, move);
}
}
Node n;
return n;
}
int main() {
array<int, 6> init_state{ 3,3,1,0,0,0 };
array<array<int, 3>, 5> moves{ { {1,0,1}, {0,1,1}, {1,1,1}, {2,0,1}, {0,2,1} } };
Node n = Node(init_state);
queue<Node> q;
q.push(n);
Node last = bfs(q, moves);
}
答案 0 :(得分:1)
我认为问题出在
void applyMoves(queue<Node> &q, Node current_node, array<int, 3> moves) {
array<int, 6> arr = current_node.arr;
array<int, 3> left, right;
// apply valid moves to arr
// copy the arr to left and right and check if the move applied are valid
// if valid and no duplicates in the queue do line 31 and 32
Node n = Node(arr, ¤t_node);
q.push(n);
}
此处current_node
是一个副本,您正在存储它的地址。当函数结束时,副本被销毁,现在你有一个悬空指针。您应该可以通过引用current_node
来修复它。
编辑:
您在
中也有同样的行为Node bfs(queue<Node> &q, array<array<int, 3>, 5> moves) {
while (!q.empty()) {
Node current = q.front();
q.pop();
if (achievedGoal(current.arr) == 1) {
return current;
}
for (const auto& move : moves) {
applyMoves(q, current, move);
}
}
Node n;
return n;
}
在这里创建current
这是一个本地自动对象,然后将队列的前端复制到其中,然后将pop()
从前面取出队列。因此,当您将此节点用于父节点时,一切都会正常,直到您转到while循环的下一次迭代。一旦你这样做current
被摧毁,这意味着指向它的一切现在正在晃来晃去。然后循环开始备份并创建一个新的current
。如果在我认为它的示例位置创建了这个对象,那么你所创建的所有节点的父节点现在都指向这个新节点。
他们目前正在做的事情不会起作用。我不太确定你应该如何改变它以获得正确的行为。
答案 1 :(得分:0)
由于我还不能对其他人的帖子发表评论,我将以自己的答案为基础,继续前面的回答。是的,以下功能:
void applyMoves(queue<Node> &q, Node current_node, array<int, 3> moves) {
array<int, 6> arr = current_node.arr;
array<int, 3> left, right;
// apply valid moves to arr
// copy the arr to left and right and check if the move applied are valid
// if valid and no duplicates in the queue do line 31 and 32
Node n = Node(arr, ¤t_node);
q.push(n);
}
需要通过引用获取current_node,因为否则,您将一个地址存储到一个局部变量,该变量将在执行超出函数范围后被销毁。
但是,不仅如此,还有:
Node current = q.front();
q.pop();
您正在复制队列中的第一个元素,并将其保存到局部变量中,当您将其传递给上述函数时(即使是通过引用完成),您仍然会遇到同样的问题,因为你存储局部变量的地址(不同功能的局部变量,但仍然 - 同样的问题)。并且,根据发布的逻辑,我不清楚,正确的解决方案是什么,但至少你有&#34;为什么?&#34;回答。
编辑:显然,原始海报通过他的编辑打败了我。