我正在做一个项目,要求我解决一个你无法左转的迷宫。该程序工作正常,但输入非常大的情况除外。
我的一般策略是在图形中的迷宫4个节点中制作每个点,对应于UP,DOWN,LEFT和RIGHT,其中每个节点具有直线和右边缘,并且直线具有权重0和右边具有权重1.边缘在我的代码中表示为对象,并且具有指向目标节点及其原始节点的指针。
为了找到最佳路径(右转最少的路径),我使用了带有双端队列的广度优先搜索。我使用deque能够将重量1个节点推到后面并将0个节点加到前面。但是,我在搜索期间分配了少量内存,而不是在任何地方清理它,这可能导致我的程序失败非常大的迷宫输入。
这是代码(特别是用于检查BFS中节点的相邻边的for循环):
//t is a node object in the graph that has been popped out of the deque
//loop that checks each adjacent node from t (adj is a vector of edges)
for(unsigned int i = 0; i < t.adj.size(); i++)
{
if(!t.adj[i].used)
{
if(!t.adj[i].dest->visited)
{
//Memory leak location
t.adj[i].dest->prev = new node(t);
t.adj[i].used = true;
//weight of an edge is 1 if it's a right turn, 0 otherwise
if(t.adj[i].weight == 1)
{
//put the heavier nodes on the end of the queue
nodes.push_back(t.adj[i].dest);
}
//0-weight nodes on the top
else nodes.push_front(t.adj[i].dest);
}
}
我一直在试图弄清楚如何更好地修剪搜索以及如何在我绝对不再需要这些节点时释放这种分配。但我需要一些方向来考虑这个问题。如果需要其他代码,请告诉我。
感谢。
编辑:节点和边缘类(请原谅我对标准类设计原则的忽视,只是快速将它们放在一起):
class node
{
public:
node();
node(Direction d, int r, int c, NodeType t);
~node(); //empty definition
node(const node* n);
node(const node& n);
node& operator=(const node& n);
node& operator=(const node* n);
void addAdj(node* a, int w);
void printAdj() const;
string direction() const;
void print() const;
bool operator<(const node& n) const;
int distance; //from start
bool visited;
node* prev;
vector<Edge> adj;
Direction dir;
int row, col;
NodeType type;
};
///////////////////////
struct Edge
{
Edge();
Edge(node* o, node* d, int c);
node* org;
node* dest;
int weight;
bool used;
};
答案 0 :(得分:1)
如果node
指向t
(因此您不需要t
类型的完全定义node
?){{1 }}的声明并按node::adj[]::dest::prev
的值{而不是动态分配}来获取node
?
这将确保您不会泄漏内存,因为您没有动态分配任何内容。缺点是,一旦t.adj[i].dest->prev
超出范围,您需要确保t
没有引用dest::prev
。
在这种情况下,您可以更改行
t
到
t.adj[i].dest->prev = new node(t);
您需要一个特殊值来表示无效的t.adj[i].dest->prev = node(&t);
(之前为NULL)。也许使用prev
?
替代方法:使用共享指针(如果您不使用C ++ 11,则BOOST提供选择)以确保在所有引用都消失时自动释放。您将不得不确保永远不会保留循环引用,从而阻止“zombi”节点的重新分配(不会再次使用的节点,但由于仍有对它们的引用而无法取消分配