简体   繁体   中英

Recursively inserting into a binary tree, passing pointer by value?

Here is my Node class.

class Node
{
private:
public:
  T data;
  Node<T>* left;
  Node<T>* right;
  Node(T dat) : data(dat), left(NULL), right(NULL)
  {}
};

Here is my insert function, defined in my Btree class:

public:
  Node<T>* root;
  Btree() : root(NULL){}
  void insert(T data, Node<T>* parent)
  {   
      if( !parent  )
      {   
        parent = new Node<T>(data);
        return;
      }   
      else if(data < parent->data)
      {   
        insert(data, parent->left);
      }   
      else if(data > parent->data)
      {   
        insert(data, parent->right);
      }   
  }

};

Here is my main function:

int main()
{
  Btree<int> tree;

  tree.insert(5, tree.root);

  cout << tree.root->data << endl;

  tree.insert(6, tree.root);

  cout << tree.root->right->data << endl;

}

When I run, I get a seg fault.

I think it is because the pointer variable parent is passed by value, so when I create a new Node that is pointed to by parent, once I exit the insert function I lose it? Does that mean I have to use a double pointer here?

Can someone give me a thorough explanation about what's going on in memory that is making this not work out as planned. Is my diagnosis correct here or is there something else wrong?

When I pass tree.root as the second parameter to insert, I am passing a Node*, I know that much. Now, even if it is passed by value, will it not be the same address that I passed from the invoking main function. So when I say parent (which is the address which I passed from main, tree.root) = new Node, should that not create a new Node on the heap that at the address of parent, aka the address of tree.root? Why does passing by value fudge this up?

The problem with passing by value in this case is that all assignments made to the formal argument inside the function are not visible to the caller. Therefore, this assignment

if( !parent  )
{   
    parent = new Node<T>(data); // <<== HERE
    return;
}

has no effect on the tree.root in the caller:

tree.insert(5, tree.root);

The value of the parent pointer in the function is changed, and then promptly discarded; tree's root remains NULL .

A fix to this problem would be passing a pointer to a pointer, like this:

void insert(T data, Node<T>** parent) {
    if( !*parent  )
    {
        *parent = new Node<T>(data);
        return;
    }
    else if(data < (*parent)->data)
    {
        insert(data, &((*parent)->left));
    }
    else if(data > (*parent)->data)
    {
        insert(data, &((*parent)->right));
    }
}

C++ passes by value, so that parent is a copy of the passed-in pointer. Assigning to it therefore has no lasting effect. The easiest way to fix this is to change the signature of the method so that it accepts a reference to the pointer. This will automatically make the compiler update the original pointer while avoiding having to the change the rest of the program.

dasblinkenlight answered it best. But, there is a more succinct solution:

Get the reference of the pointer (known as reference to pointer):

void insert(T data, Node<T>*& parent)
  {   
      if( !parent  )
      {   
        parent = new Node<T>(data);
        return;
      }   
      else if(data < parent->data)
      {   
        insert(data, parent->left);
      }   
      else if(data > parent->data)
      {   
        insert(data, parent->right);
      }   
  }

See more here: http://www.codeproject.com/Articles/4894/Pointer-to-Pointer-and-Reference-to-Pointer

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