【问题标题】:c++ pointer manipulation problem with linked list insert at head for a graphc++ 指针操作问题,链表在图的头部插入
【发布时间】:2021-03-24 14:59:01
【问题描述】:

我有一个存储链表数组的 Graph 类。 我想在链表的头部插入并将新项目的“下一个”设置为前一个头部。 但是,当我将新头的“下一个”设置为前一个头时,它最终会将新头设置为自己的下一个,从而导致无限循环,因为下一个也指向自身。 特别是 insert() 中的这一行

EdgeNode node = EdgeNode(y, weight, edges[x].isEmpty() ? nullptr : &edges[x]); 

node 对象对它自己和下一个对象都有正确的和预期的值。 但是,一旦我将 node 分配给数组,

    edges[x] = node;//This causes "next" to contain its own reference., causing circular dependency

它变坏了,并将 edges[x].getnext() 也分配为 edges[x] 导致循环引用。 我什至有自己的重载赋值运算符,但它没有帮助。 我认为它归结为简单的指针操作。除了如何修复它,请解释为什么它不起作用。不想使用智能指针或将链表对象数组更改为指针数组。

最后是 Graph 类和 main()

#include <iostream>

const int MAX_VERTICES = 1000;
class EdgeNode {
    int y{ -1 };
    int weight{ 1 };
    EdgeNode* next{ nullptr };  
public: 
    EdgeNode() : y(-1), weight(1), next(nullptr) {}
    EdgeNode(int _y, int _weight, EdgeNode* _next) : y{ _y }, weight{ _weight }, next(_next) {}
    EdgeNode& operator=(const EdgeNode& other) {
        this->next = other.getNext();
        this->y = other.getY();
        this->weight = other.getWeight();
        return *this;
    }
    int getY() const { return y; } ;
    int getWeight() const { return weight; };
    EdgeNode* getNext() const { return next; };
    bool const isEmpty() { return y == -1; }
};

class Graph {
    EdgeNode edges[MAX_VERTICES];   
public:
    Graph() {};
    void insertEdge(int x, int y, int weight, bool directed) {
        EdgeNode node = EdgeNode(y, weight, edges[x].isEmpty() ? nullptr : &edges[x]);
        edges[x] = node;//This causes "next" to contain its own reference., causing circular dependency
        if (directed) {
            insertEdge(y, x, weight, false);
        }
    }
};

int main()
{
    std::cout << "Hello World!\n";
    Graph graph;    
    graph.insertEdge(1, 11);
    graph.insertEdge(1,  111);
}

【问题讨论】:

    标签: c++ pointers graph linked-list


    【解决方案1】:

    问题出在这里:

    EdgeNode edges[MAX_VERTICES];
    

    你有一个对象数组。

    当您覆盖列表中的元素时,该对​​象不再存在,因此您无法创建链。

        // This creaters a local object.
        // When this function exits this object will no longer exist.
        // Which is fine for the first element in the list (as you copy it).
        // But for the second and third etc this does make a difference  
        EdgeNode node = EdgeNode(y, weight, edges[x].isEmpty() ? nullptr : &edges[x]);
    
    
        // Here you copy "node" into `edges`.
        // BUT you are overwritting the current head
        // not adding a new node.
        edges[x] = node;
    

    解决这个问题:

    EdgeNode* edges[MAX_VERTICES];   // an array of pointer.
    
    // ----
    EdgeNode*  node = new EdgeNode(y, weight, edges[x].isEmpty() ? nullptr : &edges[x]);
                      ^^^ note the new
    edges[x] = node;
    

    这里有几个问题。我没有添加代码来管理对象。与所有资源管理一样,确保此列表保持同步变得很困难。您可以通过多种方式解决此问题。


    技巧一:使用智能指针。

    std::unique_ptr<EdgeNode> edges[MAX_VERTICES];
    
    // ----
    std::unique_ptr<EdgeNode>  node = std::make_unique<EdgeNode>(y, weight, edges[x].isEmpty() ? nullptr : &edges[x]);                      
    edges[x] = std::move(node);
    
    // Note: Not quite that simple
    //       You need to extract objects from the list
    //       Which implies the object next should also be a smart pointer
    //       which then implies move rather than assign.
    

    技巧 2:使用标准容器:

    std::list<EdgeNode> edges[MAX_VERTICES];
    
    // ----
    EdgeNode  node = EdgeNode(y, weight); // Let the list handle next/prev for you
    edges[x].push_front(node);
    

    【讨论】:

    • 有没有办法将现有元素复制或移动为新头部中的“下一个”?像 &edges[x] 的深拷贝?如果可以用指针做某事,也可以用普通对象做?
    • @bsobaid 不在您当前的设计中。要使用指针并拥有扩展列表,您需要动态分配对象。
    猜你喜欢
    • 2011-05-16
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-07
    • 2019-04-20
    相关资源
    最近更新 更多