将指向列表中元素的指针插入地图会导致垃圾值
我试图实现 Prim 的算法(急切),它需要跟踪到顶点的最佳输入边(最低成本)。为此,我将 stl map 用作:
std::map<int, Edge*> bestEdgeFor;
但是,当我尝试为某个键分配边时,实际存储的是带有数据成员垃圾值的边。因此,我得到一些随机边缘作为输出。但是,当我使用相同的数据分配 Edge 类的新实例时,它可以正常工作。
bestEdgeFor[destNode] = &e; //Doesn't work
bestEdgeFor[destNode] = new Edge(e.from,e.to,e.cost); // Works
这是 Edge 类定义:
class Edge {
public:
int from;
int to;
int cost;
};
我无法弄清楚到底是什么问题。是不是我们不能直接分配一个类的对象?请原谅我的天真。
这是Graph类,我在这个类的一个成员函数中进行赋值操作。e来自adjList. 范围有效吗?
class Graph {
int V;
std::map<int, std::list<Edge>> adjList;
map<int, Edge*> bestEdgeFor;
public:
void relaxEdgesAtNode(int currentNode, MinIndexedPQ& ipq, int* visited){
visited[currentNode] = 1;
for(Edge e : adjList[currentNode]) {
int destNode = e.to;
if(visited[destNode]){
continue;
}
if(!ipq.contains(destNode)) {
ipq.insert(destNode,e.cost);
// bestEdgeFor[destNode] = &e // Don't work
bestEdgeFor[destNode] = new Edge(e.from,e.to,e.cost); // Works
} else {
if(e.cost < ipq.keyOf(destNode)) {
ipq.decreaseKey(destNode,e.cost);
// bestEdgeFor[destNode] = &e // Don't work
bestEdgeFor[destNode] = new Edge(e.from,e.to,e.cost);
}
}
}
}
std::vector<Edge*> primsMST() {
int s = 0; //choosing the starting node
int* visited = new int[V]{0};
MinIndexedPQ ipq(V);
visited[s] = 1; // marking the starting node visited
int m = V - 1;
int edgeCount = 0, mstCost = 0;
std::vector<Edge*> mstEdges; // This is the return value in case the mst exists
// Call the problematic function
relaxEdgesAtNode(s, ipq, visited);
// Here, the values are garbage, and the printing code prints garbarge
}
};
回答
这是Graph类,我在这个类的一个成员函数中进行赋值操作。
e来自adjList. 范围有效吗?
通常,是的。这是因为链表中的对象具有稳定的地址。只要它们在列表中,您就可以获取它们的地址并将指针放入映射中而不会出现问题。
现在让我们看看你的任务:
范围有效吗?
bestEdgeFor[destNode] = &e; //Doesn't work
但什么是e?你如何初始化它?让我们来看看:
for (Edge e : adjList) {
// ... much code ...
bestEdgeFor[destNode] = &e;
}
在此代码中,e是循环范围内的局部变量,您从列表中的值复制初始化。
e来自adjList
这不是真的。e不要来自adjList. 正如您的代码中所见,e是循环内的一个局部变量,它具有从其他地方复制的值,在您的情况下是列表。您获取将在循环迭代后消亡的局部变量的地址。
你想要做的很可能是这样的:
// something similar to this
for (Edge& e : adjList) {
// ... much code ...
bestEdgeFor[destNode] = &e;
}
现在e是对列表中变量的引用。当你获取 的地址时e,你获取了一个指向列表元素的指针。
但是,请注意从列表中的元素获取指针需要特别注意。一旦从中删除元素,就必须更新映射并删除所有指向该删除元素的指针。