繁体   English   中英

二叉树中的节点为空

[英]Nodes in binary tree are null

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的节点。

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

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

第2行已注释掉。

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

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

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

指针持有地址的变量。 他们没有什么魔力。 第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,则会自动创建一个新节点并使其成为根节点。

这里发生了什么:

    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-> 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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM