0

I have a binary tree that looks like this

struct Node 
{
  int key;
  double data;
  Node* right;
  Node* left;
};

and I have this "insert" function for inserting new nodes and building the tree

void insert(Node*& p, int key, double to_be_inserted) 
{
  if (p == nullptr) 
  {
    p = new Node;
    p->key = key;
    p->data = to_be_inserted;
    p->left = nullptr;
    p->right = nullptr;
  }
  else 
  {
    if (p->key == key) 
    {
      p->data = to_be_inserted;
    }
    else 
    {
      Node*& newChild = (p->key > key) ? p->left : p->right;
      insert(newChild, key, to_be_inserted);
    }
  }
}

and a main function that looks like this

int main(int argc, char ** argv) 
{
  Node* root = nullptr;
  insert(root, 11, 11);
  insert(root, 6, 6);
  insert(root, 4, 4);
  insert(root, 5, 5);
  insert(root, 8, 8);
  insert(root, 10, 10);
  insert(root, 19, 19);
  insert(root, 17, 17);
  insert(root, 43, 43);
  insert(root, 31, 31);
  insert(root, 49, 49);

  printTree(root, 0);
  return 0;
}

The final "printed-out" tree looks like this

enter image description here

(This "print-out" is meant to be read from left to right instead of top to bottom)

What I don't understand is... when does the insert function decide to backtrack (go back up the tree) and build a right subtree?

For example, if we look at insert(root, 5, 5) and insert(root, 8, 8) in main, why does the 8 end up being a child node of node 6 instead of node 5. According to the logic of the insert function, it should just keep going down the tree and making the 8 a child node of node 5... right?

I need help properly understanding the insert function. I am sure that I am misunderstanding something in it's logic.

Thanks (and sorry for the long post)!

Schytheron
  • 715
  • 8
  • 28
  • _when does the insert function decide to backtrack_ There is no backtracking but just a recursive traversing to find the right node for insertion, here: `Node*& newChild = (p->key > key) ? p->left : p->right;`. (In case you oversaw it, that's a conditional operator - similar like an if-else but as expression.) – Scheff's Cat Feb 24 '20 at 13:52
  • @Scheff Yes, I understand that there is no backtracking in the function and that's why I am confused. When the `insert(root, 8 ,8)` line gets called in `main`, according to the logic of `insert`, shouldn't `8` become a right child of `5`? How does it end up becoming the right child of `6` instead? That's what I don't understand. When does `insert` decide to go back up the tree? – Schytheron Feb 24 '20 at 13:55
  • 8 end up being (right)child node of 6 because of this "Node*& newChild = (p->key > key) ? p->left : p->right;" every iteration you are checking if the key value is greater then current key value then go to left or else. So this condition makes it go right at 6. – rootkonda Feb 24 '20 at 13:57
  • It ends up in the last `else` branch, where it determines the left or right child to continue (with the above mentioned expression), and then it calls recursively itself for that child pointer. (...until one of the recursive calls of `insert()` doesn't end up in last `else` branch.) – Scheff's Cat Feb 24 '20 at 13:57
  • its just a tail recursion here no backtracking – rootkonda Feb 24 '20 at 13:58
  • Maybe, try step by step in a debugger to illustrate yourself how this works. (Don't forget to use Step-Into when your pointer is at `insert()`.) ;-) – Scheff's Cat Feb 24 '20 at 14:00
  • `Node*& newChild = (p->key > key) ? p->left : p->right;` -- Maybe you are confused by the syntax, and erroneously applying your logic to a misunderstanding of what that line states. In English -- *If the node I am trying to insert is less than the node in the tree I'm looking at now, take the left branch from that node, else take the right branch*. – PaulMcKenzie Feb 24 '20 at 14:02

1 Answers1

1

By the time you are inserting 8 the three looks like this (X means NULL):

insert(root, 11, 11);
insert(root, 6, 6);
insert(root, 4, 4);
insert(root, 5, 5);

        11
    6         X
 4    X    X     X
   5       

Now when you try to insert the 8(at this line Node*& newChild = (p->key > key) ? p->left : p->right; you first check if 11 > 8 which is true and thus this line is telling you that you now try to insert the 8 at the left child of 11 which happens to be rooted at 6.

At this point the insert function repeats itself, but this time the root of the three is not 11 but 6. 8 is larger than 6 and thus it goes on the right side of 6.

Thus this is the situation before and after inserting 8.


        11                             11                
    6         X                    6         X           
 4    X    X     X   =====>     4    8    X     X        
   5                             5                     

BTW, There is backtracking in this function. It is a simple recursive function.

Davide Spataro
  • 7,319
  • 1
  • 24
  • 36
  • After reading your answer, I think my confusion stems from how the pointer reference `p` (in `insert`) works. I assumed that every time `insert(root, ..., ...)` gets called, the `root` pointer changes when `p = new Node()` in `insert` gets executed. Meaning every time `insert(root, ..., ...)` gets called tree "gets" a new root (`root` pointer points to a new node). But you're saying that that is not the case? I seem to have trouble understanding how the root pointer in `main` behaves when `ìnsert` gets called. – Schytheron Feb 24 '20 at 14:15
  • I thought confusion is about where in the three the `8` get places. This has little to do with the details of the implementation. I think your misunderstanding lies in the how is the layout of the three before and after inserting `8`. If the layout of the tree before inserting `8` is correct, then you the only question you have to ask while traversing every level of the three is: am I inserting an element greater or lesser than the current root? if greater go right, otherwise go left. Is that simple. – Davide Spataro Feb 24 '20 at 14:26
  • Fair enough. It seems I don't really have a good grasp of how pointers and pointer references work then (I am new to C++). I simply don't understand what happens at the `p = new Node` line. It creates a new node for `p` to point to, but `p` is a reference to `root`, yet `root` doesn't change? And `p` is local, so as soon as the function exits, all memory of the tree is lost? How does it know what the current tree looks like once main does a new `insert` call? Shouldn't the tree be wiped from memory due to scope? I am just confused I guess, better to ask this in a new post? – Schytheron Feb 24 '20 at 14:35