0

I've got the following code:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Node
{
    int value;
    Node *left, *right;
    Node(int value, Node *l = NULL, Node *r = NULL)
    {
        this->value = value;
        left = l;
        right = r;
    }
};
struct BST
{
    Node *root = NULL;
    void insert(int value)
    {
        cout<<"Inserting: "<<value<<endl;
        Node **current = &root;
        while(*current != NULL)
        {
            if(value >= (*current)->value)
            {
                current = &((*current)->right);
            }
            else current = &((*current)->left);
        }
        (*current) = new Node(value);
    }
    void remove(int value)
    {
        Node *toRemove = search(value);
        remove(toRemove);
    }
    void remove(Node *toReplace)
    {
        if(toReplace == NULL) return;
        Node *toBeReplacedWith = NULL;

        if(toReplace->left == NULL && toReplace->right == NULL)
        {
            delete toReplace;
            toReplace = NULL;
            return;
        }
        if((toReplace->left == NULL) ^ (toReplace->right == NULL))
        {
            if(toReplace->left != NULL) toBeReplacedWith = toReplace->left;
            else toBeReplacedWith = toReplace->right;
            copyAndDeleteNode(toReplace, toBeReplacedWith);
            return;
        }
        Node *current = toReplace->left;
        while(current->right != NULL) current = current->right;
        toReplace->value = current->value;
        remove(current);
    }
    Node* search(int value)
    {
        Node *current = root;
        while(current != NULL && current->value != value)
        {
            if(current->value > value) current = current->left;
            else current = current->right;
        }
        if(current == NULL)
        {
            cout<<"The node didn't exist in the BST";
        }
        return current;
    }
    void traverse()
    {
        rec_traverse(root);
    }
private:
    void copyAndDeleteNode(Node *toReplace, Node *toBeReplacedWith)
    {
        toReplace->value = toBeReplacedWith->value;
        toReplace->left = toBeReplacedWith->left;
        toReplace->right = toBeReplacedWith->right;
        delete toBeReplacedWith;
        toBeReplacedWith = NULL;
    }
    void rec_traverse(Node * current)
    {
        if(current == NULL) return;
        rec_traverse(current->left);
        cout<<current->value<<endl;
        rec_traverse(current->right);
    }
};
int main()
{
    BST tree;
    for(int i = 0; i < 10; ++i)
    {
        tree.insert(i);
    }
    Node  *a = tree.search(6);
    cout<<"found val: "<<a->value<<endl;

    tree.remove(5);
    tree.remove(9);
    tree.remove(2);
   // tree.insert(4);
    //tree.insert(15);
    tree.insert(6);
    tree.insert(22222);
    cout<<"Traversing:\n";
    tree.traverse();
    return 0;
}

For some reason when executing, the program crashes on the insert(22222) while there is no problem on the previous calls and I can't understand why. The problem must be between lines 26-30 and I always put NULL values in the Node constructor so I'm confused why the loop doesn't break.

user1113314
  • 803
  • 1
  • 10
  • 24
  • 3
    `For some reason when executing, the program crashes` Use your debugger to determine the reason for the problem. – PaulMcKenzie Jul 09 '14 at 15:28
  • Is the value 22222 the first data item or somewhere in the middle? How many data items before the value 22222 is inserted? If you want us to debug your program for you, minimally, we'll need your test data. Have you tried other values, do they succeed or fail? – Thomas Matthews Jul 09 '14 at 15:53

1 Answers1

1

One thing right away that is wrong is this:

remove(Node* toReplace).

That function does not update your Node pointer, as you are passing the pointer by value. All of that code within that function that changes the toReplace pointer in any way is thrown away as soon as remove returns.

For example, these lines:

delete toReplace;
toReplace = NULL;

The delete is done, but setting the pointer to NULL does nothing, as again, the toReplace is a local variable.

You need to change your prototype to this:

remove(Node *& toReplace).

Passing a reference to the pointer now allows the pointer value to be updated and be reflected back to the caller.

Also, you did not check your tree's state after you removed the leaf node of '9'. If you did that, you should have clearly seen that your new leaf node of '8' has a bad "right" pointer. This causes all sorts of problems when you attempt to add a node (22222) that is greater than 8.

Your remove function is faulty right here:

    if(toReplace->left == NULL && toReplace->right == NULL)
    {
        delete toReplace;
        toReplace = NULL;
        return;
    }

OK, so you removed the node (assume it is the '9' node). So what about the node that used to point to '9'? You didn't adjust its right (or left) pointers to now point to NULL. That's where the problem starts.

All of these could have been detected if you merely looked at your tree to see if it is still correct after each operation. You could have just used the debugger, or even just printed out the state of the tree at each stage.

Lastly, your tree struct lacks a destructor. You allocate memory, but nowhere is it deallocated.

Edit:

What is this line supposed to do? More specifically, what is that ^ supposed to do?

if((toReplace->left == NULL) ^ (toReplace->right == NULL))  
PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45
  • Thanks for the information, good to know. But even after making the changes(passing a pointer to a pointer?) the program still crashes on insert(22222) – user1113314 Jul 09 '14 at 17:55
  • Can you give me a link because I got no idea how to do that. My IDE is Code::Blocks if that matters. I find working with pointers to be the hardest part of C/C++ and difficult to reason about, e.g it took me 1-2 hours to make the code work and still failed. – user1113314 Jul 09 '14 at 18:48
  • Please do a web search, as I did here: https://www.google.co.uk/?gfe_rd=cr&ei=5py9U774CqzR8gewioDwBA&gws_rd=ssl#q=codeblocks%20debugger%20tutorial – PaulMcKenzie Jul 09 '14 at 19:52
  • Well, If I have 'toReplace = NULL;' doesn't that make the parent to point to NULL, too? – user1113314 Jul 09 '14 at 20:36
  • And as for the ^, I ensure that the current node has exactly one child set, so i can just put the child in the place of the current node and maintain the BST property. – user1113314 Jul 09 '14 at 20:38
  • `Well, If I have 'toReplace = NULL;' doesn't that make the parent to point to NULL, too?` No. You don't need a BST to show this: `int main() { int x = 10; int *pX1 = &x; int *pX2 = pX1; pX1 = 0; }` You will see that pX2 doesn't change value just because pX1 was set to 0. – PaulMcKenzie Jul 09 '14 at 20:40