二叉树中的节点为空

时间:2014-03-09 03:27:29

标签: c++ tree binary-tree

void MultiMap::insert(string key, unsigned int value)
{
    if(head == nullptr)
        head = new Node(key, value);
    else
    {
        Node* tempNode = head;
        while(tempNode != nullptr)
        {
            if(key <= tempNode->m_key)
                tempNode = tempNode->m_left;
            else if(key > tempNode->m_key)
                tempNode = tempNode->m_right;
        }
        /*line 1*/tempNode = new Node(key, value);
        //*line 2*/head->m_left = new Node(key, value);
    }
}

对于赋值,我必须创建一个二叉树类,“MultiMap”,其中包含一个包含字符串和int的节点。

以上是将新节点插入树中的代码。节点按字符串排序。如果我尝试插入的节点的字符串是&gt;当前节点,程序应该尝试将其插入树的右侧分支,如果它是&lt; =,程序应该尝试将其插入树的左侧分支。

我通过尝试按顺序插入两个节点:(Joe,5)和(Bill,1)来测试它,所以如果程序正常工作,“bill”应该在“joe”的左侧分支上。 / p>

第2行被注释掉了。

如果我使用第1行,程序会编译并“插入”第二个节点,但是当我尝试使用其他代码查找它时,它只会找到一个nullptr。如果我用第2行替换第1行,程序将按预期工作。

“tempNode”是我用来跟踪树以找到插入新节点的适当位置的方法。 “head”是指向树中第一个节点的指针。 “m_left”和“m_right”是指向节点的指针,分别代表节点的左右分支。

我不知道为什么这两行不会做同样的事情,即使在那一点上,似乎tempNode和head-&gt; m_left指向内存中的相同位置:第一个的左分支节点

2 个答案:

答案 0 :(得分:1)

指针是保留地址的变量。他们没有什么魔力。第1行执行此操作:

tempNode = new Node(key, value); 

这不会在树中插入任何内容。实际上,它只会泄漏内存。

tempNode指向之前此语句的内容无关紧要。更重要的是, tempNode如何保持先前的值已经丢失,因为您已经从树下降了一级。保持相同地址的两个指针只意味着可以使用两个指针访问该地址。为指针分配新地址对先前寻址的实体(如果有的话)无效

您的任务应该是找到应该用新分配的对象的地址填充的指针。你找到了(有点)。不幸的是,一旦你走进树中进行最后的零检测,你也会丢失它。一旦这个:

while (tempNode != nullptr)

变得虚假而且破裂,你已经是一个节点太远了。有很多方法可以解决这个问题。有些人喜欢使用“父”指针,但这只意味着你需要特殊情况下的空映射条件。请考虑一下:

void MultiMap::insert(string key, unsigned int value)
{
    // pp will always point to the pointer we're testing
    //  i.e. a pointer to pointer.
    Node **pp = &head;

    while (*pp) // while whatever pp points to is a non-null-pointer
    {
        if (key < (*pp)->m_key)
            pp = &(*pp)->m_left; // put address of left-pointer into pp

        else if ((*pp)->m_key < key)
            pp = &(*pp)->m_right; // put address of right pointer into pp

        else break; // strict weak order match 
    }

    if (*pp)
    {
        // found matching key. NOTE: unclear if you wanted to just update or not
    }
    else
    {
        // allocate new node.
        *pp = new Node(key,value);
    }
}

除了用头节点指针的地址初始化指针到指针之外,你会注意到,不再引用head。

最后,注意没有特殊情况的头节点测试。如果映射为空且头指针为NULL,则会自动创建一个新节点并使其成为根节点。

答案 1 :(得分:1)

这里发生了什么:

    Node* tempNode = head;
    while(tempNode != nullptr) 
    { 
        if(key <= tempNode->m_key)
            tempNode = tempNode->m_left;
        else if(key > tempNode->m_key)
            tempNode = tempNode->m_right;
    }

好的,现在是tempNode == nullptr它没有指向树的任何节点。因为它是堆栈上的变量,所以下一行:

    /*line 1*/tempNode = new Node(key, value);

只是初始化这个本地指针而不会影响树本身。(这里真的是内存泄漏。) 在第二行中,初始化树中的节点:

 head->m_left = new Node(key, value);

但仅限于head-&gt; m_left。 所以你可以写:

if (key <= tempNode->m_key) {
    if (tempNode->m_left == nullptr) {
         tempNode->m_left = new Node(key, value);
         break;   //  traverse tree loop
    }  else {
         tempNode = tempNode->m_left;
    }
}