为啥这个节点有自己的孩子?

Posted

技术标签:

【中文标题】为啥这个节点有自己的孩子?【英文标题】:Why does this node have itself as a child?为什么这个节点有自己的孩子? 【发布时间】:2021-11-08 22:32:48 【问题描述】:

我正在尝试在 C++ 中创建一棵节点树。本质上,我从一个按权重排序的节点向量开始,然后我运行一个循环,将向量的底部两个作为子节点创建一个新节点,从向量中删除这些子节点,并将新的父节点添加到矢量,然后排序。它似乎工作得非常好,直到它到达循环的最后一部分,它将最后两个节点组合成一个父节点。我的调试的一部分告诉我这个父母有正确的孩子,然后下一条调试消息说它有自己作为一个孩子,我不知道为什么。根据我手动设置子节点的结果,我认为由于某种原因,向量中的最后两个节点是子节点和新父节点之一,这应该是不可能的,因为我还没有添加它。以下是一些调试信息:

......

节点:

大小 = 2

183 78.275 182 55.6462

新节点有子节点 182 和 183,权重为 133.921,id 为 184

我正在开始搜索。我的 id 是 184

我有孩子。我的第一个孩子 id 是 182,我的第二个孩子是 184

我正在开始搜索。我的 id 是 182

我有孩子。我的第一个孩子 id 是 178,我的第二个孩子是 180

......

然后最终,它可以预见地沿着树向下工作,然后再次返回到第二个孩子,由于某种原因它本身就是这样,并且它陷入了循环。第一条调试消息清楚地说明了哪些节点是它的子节点,而下一条则不同意。以下是一些相关代码:

while (nodes.size() != 1)  // start combining nodes

        cout << "NODES: " << "\n\n"; // print a list of all the nodes, for me, the human
        int size = nodes.size(); // keep track of the size with an int since we know when it will change and i will be pulling for it a lot
        cout << "size = " << size << endl;
        for (int i = 0; i < size; i++) 
            cout << nodes[i].id << " " << nodes[i].character << " " << nodes[i].weight << endl;
        

        Node newNode(&nodes[size - 1], &nodes[size - 2], globalID); // create a new node with children as the two nodes at the bottom of the list, which will be the two with the lowest weight because the vector is sorted
        cout << "new node has child " << newNode.child1->id << " and " << newNode.child2->id << " with weight " << newNode.weight << " and id " << newNode.id << endl;
        nodes.pop_back(); // delete the last two nodes in the vector. there is probably a better way to do this, but this works
        nodes.pop_back();
        nodes.push_back(newNode); // add the new parent node to the end of the vector...
        sort(nodes.begin(), nodes.end(), sortNodes); // ...and sort the vector by decreasing weight. i know it would be better to just add the new node to the right spot. i couldnt figure out how, and this works
    
class Node

public:
    Node(); // default constructor
    Node(Node* cld1, Node* cld2, int& globalID); // constructor with children
    Node(char crtr, double wt, int& globalID); // constructor for a character node at the bottom of its branch

    int findDepthOfTree() const; // returns the depth of the tree below and including this node

    void setChild2(Node* chl2);

    double weight; // weight of the node
    string character; // character if the node is the bottom of the branch
    Node* child1; // the two children
    Node* child2;
    int id; // a global id so that i as a human can keep track of them
    bool hasChildren; // true if it is not a character node
;
Node::Node(Node* cld1, Node* cld2, int& globalID)  // constructor with children
    weight = cld1->weight + cld2->weight; // the weight of the parent is the sum of the childrens weights
    child1 = cld1;
    child2 = cld2;
    id = globalID; // set the id of this node and increment the global counter
    globalID++;
    hasChildren = true;

如果有什么我忘记了,请告诉我。

【问题讨论】:

您是否已经在调试器中单步执行了您的代码? 【参考方案1】:

您的Node 类存储指向子节点的指针。当您构造node 时,您在该对象中存储了两个指向nodes 向量的指针。几行之后,您调用nodes.pop_back() 两次。这会从向量中删除节点,并且您最近存储在node 中的两个指针现在悬空。任何取消引用它们的尝试都会导致未定义的行为。

在您的情况下,由于您随后使用 push_back 跟踪这两个弹出窗口以将 node 添加回向量,因此右子指针将指向新插入的节点,并且您最终会得到一个节点自己还是个孩子。

如果向量需要扩展其存储空间,任何push_back 都可以移动东西,而sort 会弄乱你可能拥有的任何树结构。

您将不得不重新考虑如何存储和操作树的节点。

【讨论】:

这很有意义。我想它会是这样的。有没有更好的方法可以通过某种方式从避免这种情况的父节点中找到子节点,或者我应该干脆不从向量中删除节点而不使用排序函数?我可以像现在一样将节点添加到向量中,而无需删除子节点,将它们标记为非活动状态,然后手动查看并每次找到权重最低的子节点。我认为这会起作用,而且我并不在乎它有多慢,但有没有更好的方法来解决它?

以上是关于为啥这个节点有自己的孩子?的主要内容,如果未能解决你的问题,请参考以下文章

xQuery,如何从带有孩子的节点获取文本?

为啥我的类节点会覆盖自己而不是创建新的节点对象

子女有恩论

java之数据结构与算法

为啥 Jest 不让我使用节点测试环境,即使他们自己更改了它?

父类中的 CSS 样式,以便一个孩子有 25% 的宽度,另一个孩子有 75% [重复]