简体   繁体   中英

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.

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".

Line 2 is commented out.

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. If I replace line 1 with line 2, the program works as expected.

"tempNode" is what I'm using to trace through the tree to find the appropriate place to insert a new node. "head" is a pointer to the first node in the tree. "m_left" and "m_right" are pointers to nodes, representing the left and right branches of a node, respectively.

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.

Pointers are variables that hold addresses. There is nothing magic about them. Line 1 does this:

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. More importantly, how tempNode held that prior value is already lost because you're already descended down the tree one level. 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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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