简体   繁体   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);
    }
}

For an assignment, I have to make a binary tree class, "MultiMap" with nodes that contain a string and an int. 对于赋值,我必须创建一个二叉树类,“MultiMap”,其中包含一个包含字符串和int的节点。

The above is code to insert a new node into the tree. 以上是将新节点插入树中的代码。 The nodes are sorted by their strings. 节点按字符串排序。 If the string of the node I am trying to insert is > the current node, the program should try to insert it on the right branch of the tree, and if it is <=, the program should try to insert it on the left branch of the tree. 如果我尝试插入的节点的字符串是>当前节点,程序应该尝试将其插入树的右侧分支,如果它是<=,程序应该尝试将其插入左侧分支这棵树

I tested it by trying to insert two nodes: (Joe, 5) and (Bill, 1) in that order, so if the program works properly, "bill" should be on the left branch of "joe". 我通过尝试按顺序插入两个节点来测试它:(Joe,5)和(Bill,1),所以如果程序正常工作,“bill”应该在“joe”的左侧分支上。

Line 2 is commented out. 第2行已注释掉。

If I use line 1, the program compiles and "inserts" the second node, but when I try to look for it with other code, it only finds a nullptr. 如果我使用第1行,程序将编译并“插入”第二个节点,但是当我尝试使用其他代码查找它时,它只会找到一个nullptr。 If I replace line 1 with line 2, the program works as expected. 如果我用第2行替换第1行,程序将按预期工作。

"tempNode" is what I'm using to trace through the tree to find the appropriate place to insert a new node. “tempNode”是我用来跟踪树以找到插入新节点的适当位置。 "head" is a pointer to the first node in the tree. “head”是指向树中第一个节点的指针。 "m_left" and "m_right" are pointers to nodes, representing the left and right branches of a node, respectively. “m_left”和“m_right”是指向节点的指针,分别代表节点的左右分支。

I don't know why the two lines don't do the same thing even though at that point, it seems like tempNode and head->m_left are pointing to the same location in memory: the left branch of the first node. 我不知道为什么这两行不会做同样的事情,即使在那一点上,似乎tempNode和head-> m_left指向内存中的相同位置:第一个节点的左分支。

Pointers are variables that hold addresses. 指针持有地址的变量。 There is nothing magic about them. 他们没有什么魔力。 Line 1 does this: 第1行执行此操作:

tempNode = new Node(key, value); 

This doesn't insert anything into your tree. 这不会在树中插入任何内容。 In fact, it just leaks memory. 事实上,它只是泄漏了内存。

What tempNode pointed to prior to this statement is irrelevant. 此语句之前指向的tempNode是无关紧要的。 More importantly, how tempNode held that prior value is already lost because you're already descended down the tree one level. 更重要的是, tempNode 如何保持先前的值已经丢失,因为你已经从树下降了一级。 Two pointers holding the same address just means the address is reachable with two pointers. 保持相同地址的两个指针只意味着可以使用两个指针访问该地址。 Assigning a new address to a pointer has no effect on the previously addressed entity (if there was any). 为指针分配新地址对先前寻址的实体(如果有的话) 没有影响

Your task should be finding the pointer that should be filled in with the address of a newly allocated object. 您的任务应该是找到应该用新分配的对象的地址填充的指针 You found it (sort of). 你找到了(有点)。 Unfortunately you also lost it as soon as you walked into it with your step "down" the tree for the final null-detection. 不幸的是,一旦你走进树中进行最后的零检测,你也会丢失它。 As soon as this: 一旦这个:

while (tempNode != nullptr)

becomes false and breaks, you're already one node too far. 变得虚假和破碎,你已经是一个节点太远了。 There are a number of ways to handle this. 有很多方法可以解决这个问题。 Some people like using a "parent" pointer, but that just means you have to special-case an empty map condition. 有些人喜欢使用“父”指针,但这只意味着你需要特殊情况下的空映射条件。 Consider this instead: 请考虑一下:

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

And you'll notice other than initializing our pointer-to-pointer with the address of the head node pointer, head is never referenced again. 除了用头节点指针的地址初始化指针到指针之外,你还会注意到,不会再次引用head。

Finally, notice there is no special-case head-node test. 最后,注意没有特殊情况的头节点测试。 If the map is empty and the head pointer is NULL, this will automatically create a new node and make it the root. 如果映射为空且头指针为NULL,则会自动创建一个新节点并使其成为根节点。

What is going on here: 这里发生了什么:

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

OK, now tempNode == nullptr , and it does not point to any node of the tree . 好的,现在tempNode == nullptr它不指向树的任何节点 As it is the variable on the stack, the next line: 因为它是堆栈上的变量,所以下一行:

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

just initializes this local pointer and does not affect the tree itself. 只是初始化这个本地指针, 不会影响树本身。 (Really here will be a memory leak.) In your second line you initialize the node in the tree: (这里真的是内存泄漏。)在第二行中,初始化树中的节点:

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

But only for head->m_left. 但仅适用于head-> m_left。 So you can write: 所以你可以写:

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