【问题标题】:Insert into n-ary tree using Queue使用Queue插入n叉树
【发布时间】:2015-08-11 21:31:05
【问题描述】:

我有一个简单的 n 元(最多 3 个子节点),其中插入的第一个节点将是根。之前,我添加任何其他节点,如果满足条件,我必须搜索树并从先前插入的节点插入作为子节点。 我的插入方法在第一次插入和后续插入时都被重载了。

我能够使用这种方法插入第一个节点:

void Tree::AddSkill(char* name, char* desc, int level)
{
    Skill s(name, desc, level);
    Node * newNode = new Node(s);
    //newNode->aSkill = Skill(name, desc, level);

    newNode->parent = NULL;
    for (int i = 0; i<CHILD_MAX; i++)
    {
        newNode->children[i] = NULL;
    }

    if (this->root == NULL)
    {
        this->root = newNode;
    }
    else
    {
        this->root->parent = newNode;
        newNode->children[0] = this->root;
        this->root = newNode;
    }
}

我在随后插入树时遇到了一些问题, 这是我到目前为止的代码:

void Tree::AddSkill(char* name, char* desc, int level, char* parentName)
{
    if (this->root == NULL)
    {
        cout << "Error: no nodes in tree.\n";
        return;
    }

    Node* node = NULL;
    Skill s(name, desc, level);
    Node * child = new Node(s);
    while (root != NULL)
    {
        if (strcmp(child->aSkill.GetName(), parentName) == 0)
        {
            for (int i = 0; i < CHILD_MAX; i++)
            {
                if (node->children[i] == NULL)
                {
                    child->aSkill = s;
                    child->parent = node;
                    node->children[i] = child;
                    return;
                }
            }
        }
    }
}

当我通过 VS 调试器运行代码时,第二个 AddSkill 方法中的 while 循环会无休止地重复。 我不太确定自己做错了什么或需要实施什么概念,我们将不胜感激。

附:这是一个作业(不确定合适的标签是什么)。

更新: 我尝试使用队列实现重载的AddSkill()。 这是我尝试过的。

void SkillTree::AddSkill(char* name, char* desc, int level, char* parentName)
{
    if (this->root == NULL)
    {
        cout << "Error: no nodes in tree.\n";
        return;
    }  
    queue<Node*> q;
    q.push(this->root);
    while (!q.empty())
    {
        Node * n = q.front();
        q.pop();    
        if (strcmp(n->aSkill.GetName(), parentName) == 0)
        {
            for (int i = 0; i<CHILD_MAX; i++)
            {
                if (n->children[i] == NULL)
                {
                    Skill s(name, desc, level);
                    Node * child = new Node(s);
                    //When I comment out the next 3 lines, program does not crash. Not sure what the problem is here.
                    child->aSkill = s;
                    child->parent = n;
                    n->children[i] = child;
                    return;
                }
            }
            return;
        }
        for (int i = 0; i<CHILD_MAX; i++)
        {
            if (n->children[i] != NULL)
            {
                q.push(n->children[i]);
            }
        }
    }
}

技能类

#include <iostream>
#include "Skill.h"
Skill::Skill()
{
    name = NULL;
    desc = NULL;
    level = 0;
}

Skill::Skill(char* name, char* desc, int level) : level(level), name(new char[strlen(name) + 1]), desc(new char[strlen(desc) + 1])
{
    strcpy_s(this->name, (strlen(name) + 1), name);
    strcpy_s(this->desc, (strlen(desc) + 1), desc);
}

Skill::Skill(const Skill& aSkill)
{
    this->name = new char[strlen(aSkill.name) + 1];
    strcpy_s(this->name, (strlen(aSkill.name) + 1), aSkill.name);

    this->level = aSkill.level;

    this->desc = new char[strlen(aSkill.desc) + 1];
    strcpy_s(this->desc, (strlen(aSkill.desc) + 1), aSkill.desc);
}

Skill& Skill::operator=(const Skill& aSkill)
{
    if (this == &aSkill)
        return *this;
    else
    {
        delete[] name;
        delete[] desc;

        name = new char[strlen(aSkill.name) + 1];
        strcpy_s(name, (strlen(aSkill.name) + 1), aSkill.name);

        desc = new char[strlen(aSkill.desc) + 1];
        strcpy_s(name, (strlen(aSkill.desc) + 1), aSkill.desc);

        level = aSkill.level;

        return *this;
    }
}

Skill::~Skill()
{
    delete[] name;
    delete[] desc;
}

char* Skill::GetName() const
{
    return name;
}
char* Skill::GetDesc() const
{
    return desc;
}
int Skill::GetLevel() const
{
    return level;
}

void Skill::Display(ostream& out)
{
    out << "- " << GetName() << " -- " << GetDesc() << " [Lvl: " << GetLevel() << "]\n";
}

节点:

    Skill aSkill;
    Node* parent;
    Node* children[CHILD_MAX];
    Node() : parent(NULL)
    {
        for (int i = 0; i < CHILD_MAX; i++)
        {
            children[i] = NULL;
        }
    };

    Node(const Skill& n) : aSkill(n), parent(NULL)
    {
        for (int i = 0; i < CHILD_MAX; i++)
        {
            children[i] = NULL;
        }
    };

这是main()的摘录

SkillTree student("Student");
    student.Display(cout);

    student.AddSkill("Alphabet","Mastery of letters and sounds",0);
    student.Display(cout);

    student.AddSkill("Reading","The ability to read all manner of written material",1,"Alphabet");
    student.AddSkill("Writing","The ability to put your thoughts on paper",1,"Alphabet");
    student.Display(cout); 
student.AddSkill("Speed Reading Level 1","Read any text twice as fast as normal",5,"Reading");
student.AddSkill("Speed Reading Level 2","Read any text four times as fast as normal",10,"Speed Reading Level 1");
student.AddSkill("Memorization","Memorize average sized texts",10,"Reading");
student.AddSkill("Massive Memorization","Memorize large sized texts",20,"Memorization");
student.AddSkill("Spell Writing","The ability to write spells",5,"Writing");
student.AddSkill("History","The ability to write (and rewrite) history",10,"Writing");
student.AddSkill("Written Creation","The ability to write things into reality",20,"History");
student.Display(cout);

student.Display(cout);调用的两个函数如下

    void Tree::Display(ostream& out)
{
    out << "Skill Tree: " << title << "\n";
    if (this->root == NULL)
    {
        cout << "Empty\n";
        return;
    }
    else
        Display_r(out, this->root, 1);
}

void Tree::Display_r(ostream& out, Node* n, int depth)
{
    for (int i = 0; i<depth; i++)
    {
        out << "  ";
    }
    n->aSkill.Display(out);

    for (int i = 0; i<CHILD_MAX; i++)
    {
        if (n->children[i] != NULL)
        {
            Display_r(out, n->children[i], depth + 1);
        }
    }
}

如果我在AddSkill() 的队列实现中注释掉一段代码,我不会收到错误。

【问题讨论】:

  • 它无限循环,因为root is never NULL。还能有什么其他原因?如果问题是“为什么 root 永远不会变为 NULL”,那么这应该在您的原始设计中解决(希望您在编写代码之前先在纸上做到这一点)。
  • 只是一个提示,当您检查验证时添加一些调试消息,以便您知道它到达的位置和没有到达的位置。
  • 您永远不会在循环中更改 root,因此 while 条件始终为真。
  • 您编辑的代码的问题可能与Skill类有关。你能告诉我们技能构造函数和技能复制构造函数和技能赋值运算符吗?
  • @Christophe 添加了技能 ctor、复制 ctor 和赋值运算符。

标签: c++ data-structures tree


【解决方案1】:

在第一个AddSkill() 中,您将新节点插入树的顶部,使其成为新根。

在第二个AddSkill() 中,您打算插入新节点作为父技能的子节点。方法似乎是:

  • 检查树中是否至少有一个节点(初始 if)
  • 遍历树找到父节点(while循环)
  • 如果找到父项,则找到第一个空子项插入新技能(内for循环)

有什么问题?

你的算法有几个缺陷:

  • 你在root 上循环而不是空。由于此处的树不是空的,并且您没有删除任何节点,因此该条件将保持为真,从而允许无限循环。
  • 然后您检查新孩子的姓名是否与父母姓名相对应。我认为这在大多数情况下都是错误的(否则你需要少一个参数)。所以这将确保循环是无限的。
  • 稍后您假设node 是当前节点,并将新的child 插入node 的子节点。此代码未执行。幸运的是:这将是未定义的行为,因为您已将 node 设置为 NULL 并且从未更改此值。

如何解决?

要正确执行此操作,您必须从 noderoot 开始,然后检查节点的名称是否与 parentname 匹配,如果是,则照常插入子节点。

还有最后一个问题。比较重要的一个。您的算法结构适用于链表遍历,但不适用于tree traversal。树遍历算法需要一个堆栈/列表来跟踪所有要探索的分支,或者一个递归方法。

这里有一些代码(对不起,我已经用string 替换了char* 并使用vector&lt;Node*&gt; 而不是Node*[]),使用AddSkill() 的辅助重载来执行递归搜索:

// replaces the former one that you had
void Tree::AddSkill(string name, string  desc, int level, string parentName)
{
    if (root == NULL)
    {
        cout << "Error: no nodes in tree.\n";
        return;
    }
    Skill s(name, desc, level);
    AddSkill(root, s, parentName); 
}

// auxiliary helper
void Tree::AddSkill(Node*node, Skill& s, string& parentName)
{
    if (node->sk.name == parentName) {  // if found, add the new node as childen
        Node * child = new Node(s);
        child->parent = node;
        node->children.push_back(child);
    }
    else {
        for (auto &x : node->children)   // for all the children 
            AddSkill(x, s, parentName);  // search recursively   
    }
}

这里是online demo,使用共享指针而不是原始指针。

【讨论】:

  • 感谢您的回复。我在看到你的编辑之前更新了。我尝试使用队列实现AddSkill()。请查看我的问题更新。
  • 编辑好多了!从树的角度来看,您的算法似乎运行良好,并且没有理由崩溃。我怀疑在您的 Skill 构造函数中,您分配并克隆了 c 字符串,并且您还没有为它定义 operator=。因此,像child-&gt;aSkill = s; 这样的每个赋值(顺便说一下,不需要,因为您的节点构造函数已经基于 s)可能会创建悬空指针。
猜你喜欢
  • 2015-02-13
  • 2019-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2010-10-26
  • 2016-01-17
相关资源
最近更新 更多