【问题标题】:Tree Nodes Getting Lost树节点丢失
【发布时间】:2016-12-26 23:24:12
【问题描述】:

所以我正在尝试做一个在线作业(这不是为了课程学分,我是通过 coursera 自己承担)并且我对正在发生的事情感到非常困惑。

我们得到一个 2 行输入。第一行是树中的顶点数。第二行列出所有节点的父节点,-1 表示它是根节点。

例如,给定以下输入:

5

4 -1 4 1 1

第一行说总共有 5 个节点。第二行说节点 0 是节点 4 的子节点,节点 1 是根,节点 2 是节点 4 的子节点,节点 3 是节点 1 的子节点,节点 4 是节点 1 的子节点。

现在我只是尝试读取输入并将其存储在树结构中。

#include <iostream>
#include <vector>


using namespace std;

struct Node{
    int key;
    vector<Node*> children;
};


void display(Node* root){
    cout << "My Value is " << root->key << endl;
    cout << "My children are ";
    for (int i = 0; i < root->children.size(); i++){
        cout << root->children[i]->key << " ";
    }
    cout << endl;
    for (int i = 0; i < root->children.size(); i++){
        display(root->children[i]);         //call display on all children
    }
    cout << endl;
}

int main(){

    Node* root = NULL;
    int numOfNodes;
    cin >> numOfNodes;

    int input;
    vector<int> parents;
    for(int i = 0; i < numOfNodes; i++){
        cin >> input;
        parents.push_back(input);
    }

    for(int i = 0; i < parents.size(); i++){
        Node *newNode = new Node();
        newNode->key = i;
        if(parents[i] == -1){ //root node is indicated with a -1 in input
            root = newNode;
        }
        for (int j = 0; j < parents.size(); j++){
            if(parents[j] == i){
                Node *childNode = new Node();
                childNode->key = j;
                newNode->children.push_back(childNode);
                cout << "value " << newNode->key << " is now a parent of " << childNode->key << endl;
                //delete childNode;
            }
        }
    }
    display(root);

    return 0;
}

我添加了显示功能以查看我是否正确存储了树,这就是我迷路的地方。我添加的打印语句似乎有冲突。在main中,每当我添加一个childNode时,我都会添加一个cout,但是当我的程序进入显示功能时,似乎由于根节点的子节点的异常而丢失了childNodes。这是我的输出示例。

./treeheight
5
4 -1 4 1 1
value 1 is now a parent of 3
value 1 is now a parent of 4
value 4 is now a parent of 0
value 4 is now a parent of 2
My Value is 1
My children are 3 4 
My Value is 3
My children are 

My Value is 4
My children are 

似乎在 main 中创建树的工作如我所愿,但是当我尝试在 display 中引用那些相同的节点时,出现了我不明白的错误。我原以为显示中的输出会显示为

My Value is 1
My children are 3 4 
My Value is 3
My children are 

My Value is 4
My children are 2 0

如果有人能对这里发生的事情有所了解,我将不胜感激。

【问题讨论】:

  • Node *newNode = new Node(); -- 查看您的代码,如果if(parents[i] == -1) 为假,您将不会存储此指针。因此是内存泄漏。

标签: c++ tree


【解决方案1】:

Coursera 摇滚!

同时分配节点并连接它们会使您的算法混乱。我将这两个任务分开,结果似乎按预期工作。这通常是一种很好的设计模式,将任务分开并独立完成。

错误检查受到限制,因此垃圾输入可能会导致崩溃。

#include <iostream>
#include <vector>


using namespace std;

struct Node{
    int key;
    vector<Node*> children;
};


void display(Node* root){
    cout << "My Value is " << root->key << endl;
    cout << "My children are ";
    for (int i = 0; i < root->children.size(); i++){
        cout << root->children[i]->key << " ";
    }
    cout << endl;
    for (int i = 0; i < root->children.size(); i++){
        display(root->children[i]);         //call display on all children
    }
    cout << endl;
}

int main(){

    Node* root = NULL;
    int numOfNodes;
    vector<Node> nodes;
    cin >> numOfNodes;

    int input;
    vector<int> parents;
    for(int i = 0; i < numOfNodes; i++){
        cin >> input;
        parents.push_back(input);
    }

    for(int i = 0; i < parents.size(); i++)  // make a vector of nodes for storage
       nodes.push_back(Node());

    for(int i = 0; i < parents.size(); i++){
        nodes[i].key = i;  // set the key on each
        if(parents[i] == -1){ //root node is indicated with a -1 in input
            root = &nodes[i];
        }
        else
        {
           nodes[parents[i]].children.push_back(&nodes[i]);  // set parent
        }
    }
    display(root);

    return 0;
}

【讨论】:

  • root = &amp;nodes[i]; 和这个:nodes[parents[i]].children.push_back(&amp;nodes[i]); 这看起来不太好。向量在调整大小时会使迭代器无效,因此您的 root 在执行时可能是垃圾。
  • @PaulMcKenzie 根指向节点向量,而推回则在特定节点的不同向量上。关于向量和指针的好点
  • 当然,如果发生失效,最简单的解决方法是更改​​为std::list&lt;Node&gt;
【解决方案2】:

i == 2时,你创建一个节点Node(1),内部循环找到Node(3)Node(4)这两个子节点。这为您提供了以下结构:

            Node(1)
             /   \
        Node(3) Node(4)

然后你将这个结构保存在root 中。所以这被保存了。之后,当i == 3 时,您创建一个新节点Node(3)。注意:这与从root 开始的树中的节点Node(3) 不同。它们具有相同的密钥,但它们是两个完全不同的节点。

i == 4 时也会发生同样的事情。您创建一个新节点 Node(4),它有两个子节点。但这与树中的节点不同。这是一个new 节点。而且由于您没有将新节点与子 Node(0)Node(1) 一起保存在任何地方,因此该节点将被删除。

所以最后,你只有root 节点和它的孩子。

对于解决方案:您必须将每个节点存储在某个地方。不要把它们扔掉。并且不要重新创建新节点,当您已经在某处创建它们时。例如,您可以使用初始 for 循环创建所有节点并将它们保存在临时向量中。然后,您将指针复制到子向量。

【讨论】:

  • 感谢您指出这一点。我了解您发现的我的逻辑缺陷,但我不确定我是否了解如何修复它。我尝试像您建议的那样创建一个临时向量,但现在所有“连接”都存储在该向量中正确吗?即当我尝试调用我的显示函数 Node(4) 是一个不同的 Node(4) 时,我的根节点指向的那个。我不确定如何将子节点实际添加到正确的节点 (4)(我的根节点指向的节点)。
  • 查看@MatthewFisher 的解决方案。他的实现正是我的意思。
  • 谢谢,我明白他的方法了。我只是想以我自己的知识知道我将如何完成我刚才描述的事情。如果我要继续使用我的“指针”方法,我将如何将子节点分配给正确的节点,而不是未连接到根的新节点
  • @EricS 您必须将中间节点存储在某处。例如,您可以使用vector&lt;Node*&gt;。在 for 循环中创建节点之前,您会询问它是否已经创建:if (vec[i] == nullptr) new_node = vec[i] = new Node(); else new_node = vec[i];
  • 或者使用完全不同的方法:使用函数generateTree(Node *root)递归生成节点。使用根节点启动此功能。在此函数中,您搜索所有子节点,将它们添加到 root-&gt;children,然后为每个子节点调用 generateTree(child)
猜你喜欢
  • 2016-03-18
  • 1970-01-01
  • 1970-01-01
  • 2011-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-21
  • 1970-01-01
相关资源
最近更新 更多