简体   繁体   English

在使用智能指针的有向加权图中删除节点的边

[英]Deleting edges for a node in a directed weighted graph that uses smart pointers

I'm pretty new to shared pointers and am trying to delete a node from the graph. 我对共享指针还很陌生,正在尝试从图中删除一个节点。 When I delete a node, the incoming and outgoing edges stored in that node will be deleted. 当我删除一个节点时,存储在该节点中的传入和传出边缘将被删除。 However, I also need to delete the outgoing and incoming edges (which is the incoming and outgoing edges of the deleted node respectively) of the node that was previously connected to the deleted node - which I call the linking node. 但是,我还需要删除以前连接到已删除节点的节点的出站和入站边缘(分别是已删除节点的入站和出站边缘),我将其称为链接节点。

The code below shows my Graph class declarations: 下面的代码显示了我的Graph类声明:

template <typename N, typename E> class Graph {

    private:
        struct Node;
        struct Edge;

        struct Node {
            N val_;
            int numEdges_;
            int numIncomingEdges_;
            std::set<std::shared_ptr<Edge>> edges_;
            std::set<std::shared_ptr<Edge>> incomingEdges_;
            Node() {}
            Node(const N x) : val_{x} { numEdges_=0; }
            void printNode(N n);
            ~Node();
            void update();
        };

        struct Edge {
            std::weak_ptr<Node> orig;
            std::weak_ptr<Node> dest;
            E val_;
            Edge(std::shared_ptr<Node> o, std::shared_ptr<Node> d, E x);
            Edge() {};
            void printEdge();
            ~Edge();
        };
..... Some code for node and edge iterators

private:
        std::map< N, std::shared_ptr<Node> > nodes_;

};

For the class to delete the node: 对于要删除节点的类:

template <typename N, typename E>
void Graph<N, E>::deleteNode(const N& node) noexcept {
    auto findNode = nodes_.find(node);
    if (findNode != nodes_.end()) {

        // find the node which has incoming edges into the deleted node and delete its edges
        for (auto edge: findNode->second->incomingEdges_) { // for each edge in node's incomingEdges_

            // get the origin node of incoming edge to deleted node through dest.lock()
            auto originNodeOfIncomingEdge = edge->dest.lock();

            auto nodeVal1 = originNodeOfIncomingEdge->val_;
            std::cout << "Print out value of origin node of incoming edge to deleted node: " << nodeVal1 << std::endl;

            auto findLinkingNode1 = nodes_.find(nodeVal1);
            std::cout << "size of edges_ in linking node before deleting its outgoing edge (which is the incoming edge of deleted node): " << findLinkingNode1->second->edges_.size() << std::endl;

            auto findEdge = findLinkingNode1->second->edges_.find(edge);
            findLinkingNode1->second->edges_.erase(findEdge);

            std::cout << "size of edges_ in linking node after deleting its outgoing edge (which is the incoming edge of deleted node): " << findLinkingNode1->second->edges_.size() << std::endl;
            --findLinkingNode1->second->numEdges_;

        }

... similar code to above for deleting the node that has outgoing edges from deleted node going into it

        findNode->second.reset(); // deletes managed object of the shared_ptr
        nodes_.erase(findNode); // removes the node from the map container

    }
}

So the main thing that is confusing me is this part, where I'm trying to delete the edge from the for-loop to delete the edge in the linked node. 因此,最让我感到困惑的是这部分,在这里我试图从for循环中删除边缘以删除链接节点中的边缘。

            auto findEdge = findLinkingNode1->second->edges_.find(edge);
            findLinkingNode1->second->edges_.erase(findEdge);

But I keep getting errors related to shared_ptr. 但是我不断收到与shared_ptr相关的错误。 First is related to the pointer: 首先与指针有关:

test8c(2863,0x7fff78df2000) malloc: *** error for object 0x7ffda2403350: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

Previously, my code for this part is findLinkingNode1->second->edges_.erase(edge); 以前,我这部分的代码是findLinkingNode1->second->edges_.erase(edge); without the findEdge. 没有findEdge。 I was able to compile without any errors, but the edge was not deleted. 我能够编译而没有任何错误,但未删除边缘。

Can someone guide me as to how can I delete the edge from edges_ successfully? 有人可以指导我如何成功地从edges_删除边缘吗? edges_ is declared as std::set<std::shared_ptr<Edge>> edges_; edges_被声明为std::set<std::shared_ptr<Edge>> edges_; as shown in the Graph class. 如Graph类所示。

The way things are structured, this is not very efficient. 事物的结构方式不是很有效。 Your Node s destructor will need to: 您的Node的析构函数将需要:

  1. Iterate over each of the Edge in the Node being destroyed. 遍历要销毁的Node中的每个Edge

  2. For each Edge get() the other Node . 对于每个Edge get()另一个Node

  3. Find the same Edge in that other Node 's list, and delete it. 在其他Node的列表中找到相同的Edge ,然后将其删除。

If this is a frequent operation, I would suggest the following refactoring: 如果这是经常的操作,我建议进行以下重构:

  1. Your Edge s hold shared_ptr s to your Node s. 您的Edgeshared_ptr保留到您的Node

  2. Your Node s hold weak_ptr s to your Edge s. 您的Node持有Edgeweak_ptr

Therefore, to delete a Node , you iterate over the node's Edge s, and delete them. 因此,要删除Node ,请遍历该节点的Edge ,然后将其删除。 After all Edge s get deleted, all shared_ptr s to the Node s go out of scope, and the node gets destroyed. 删除所有Edge之后,到Node的所有shared_ptr都超出范围,并且该节点被销毁。

If this is impractical, a less drastic redesign would be: 如果这不切实际,那么重新设计的方法就不那么激烈了:

  1. Assign a unique identifier, of some kind, to each Edge . 为每个Edge分配某种唯一的标识符。 A simple incrementing counter will do, and it might be possible to handle this in Edge 's constructor, automatically. 一个简单的递增计数器就可以了,并且有可能在Edge的构造函数中自动进行处理。

  2. Refer to all of your Edge s using their unique identifier, and instead of a std::set of shared_ptr s of Edge s, replace it with a std::map of identifiers, to the shared_ptr for that Edge . 使用其唯一标识符引用所有Edge ,而不是Edgeshared_ptrstd::set ,而是用标识符的std::map替换为Edgeshared_ptr This will make it trivial to remove each Edge from the other Node , when destroying a particular Node . 当销毁特定的Node时,从每个Node移除每个Edge变得很简单。

Rather than implementing a discrete identifier, with some care it might be possible to use raw pointers to the Edge s, with std::less<Edge *> as their strict weak ordering comparator, as an impromptu unique identifier for each edge. 除了实现离散标识符之外,还需要格外小心地使用指向Edge的原始指针,并将std::less<Edge *>作为其严格的弱排序比较器,作为每个边缘的即兴唯一标识符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM