【发布时间】:2020-04-20 08:01:39
【问题描述】:
我有两个朋友班:
class Node {
private:
unsigned id_;
bool marked_;
std::set<Node> neighbors_;
friend class Graph;
......
public:
bool operator == (const Node & other) const { return id_ == other.id(); }
bool operator < (const Node & other) const { return id_ < other.id(); }
......
};
class Graph {
private:
std::set<Node> vertices_{};
void reach_set_helper(unsigned id, std::vector<unsigned> &reach_set);
......
};
我正在尝试创建一个函数,该函数可以首先在图形vertices_ 中找到特定节点,例如节点v。然后我想更改v 的邻居的marked_ 属性。要找到v,我必须使用std::find() 方法。但是,此方法的返回迭代器不允许我更改邻居的成员变量。这是我尝试过的:
Node & s = v;
std::set<Node>::iterator pos = vertices_.find(s);
const std::set<Node> & neighbors = (pos->neighbors_);
for (std::set<Node>::iterator it = neighbors.begin(); it != neighbors.end(); it++) {
if (!it->is_marked()) {
reach_set.push_back(it->id());
it->set_marked(true);
this->reach_set_helper(it->id(), reach_set);
}
}
请注意,我必须使用const std::set<Node> & neighbors,因为我想原地更换邻居。但是我不能通过const迭代器it改变v的邻居,所以这个方法行不通。我有一种方法可以通过擦除来更改vertices_,然后通过迭代器复制回来,这不是问题。但这里不一样,我是对顶点的元素做操作,这是另一个集合。有什么建议吗?
更新
根据@walnut 的建议,我刚刚将marked_ 更改为 mutable,现在我可以编写以下代码
std::set<Node>::iterator pos = vertices_.find(s);
const std::set<Node> & neighbors = (pos->neighbors_);
for (const Node & nbr : neighbors) {
if (!nbr.is_marked()) {
reach_set.push_back(nbr.id());
Stack.push(nbr);
nbr.marked_ = true;
}
}
但是,这并没有解决问题,因为上面代码中的nbr现在丢失了自己的neighbors的信息,我仍然无法使用它来遍历图形。
这很奇怪,因为nbr 是原始图节点的引用?例如,我什至不能用它来打印我的图表!
void MtxGraph::print_graph() const {
const Node & start = *vertices_.begin();
print_graph_helper(start);
}
void MtxGraph::print_graph_helper(const Node & v) const {
std::set<Node> neighbors = v.neighbors_;
for (const Node & node : neighbors) {
std::cout << v.id() << " => " << node.id() << " => ";
print_graph_helper(node);
std::cout << std::endl;
}
}
上面的代码也不起作用,因为引用 node 不保留它所引用的对象的邻居信息。
【问题讨论】:
-
我正在使用
std::set<Node>。我的operator==由他们的id号码定义。如果id相同,则它们相等。哦,我没有可用的 C++ 17,现在对我来说似乎太花哨了。只是想知道在当前版本中是否有办法解决这个问题。 -
感谢@walnut,
operator<也是使用他们的id定义的,较小的id具有较小的价值。 -
在这种情况下,这是否回答了您的问题? (
std::set和std::map的行为方式相同)Modify key of std::map 或 How to update an existing element of std::set? 或 C++ std::set update is tedious: I can't change an element in place。另见stackoverflow.com/questions/6068167 -
您是否建议将
Node从std::set更改为std::map?如果是这样,我将如何在节点中拥有marked属性? -
不一定。我建议在链接问题的答案中使用其中一种方法(它们以相同的方式适用于
std::set和std::map):要么使marked_mutable或删除/修改/插入Node或在std::map<NodeKey, NodeValue>或(在C ++ 17中)使用@987654363将类分为键相关和键无关状态@.
标签: c++ class c++11 iterator stdset