Defining an object inside a function in a B+ tree - c++

I am trying to implement a B+ tree. This is a very small portion of the actual code. I had some problems when passing an object pointer to a function. As far as I know, those objects created inside the function are destroyed afterwards. So what would be a good way to improve this without changing the semantics and still keep the function recursive. Any feedback would be appreciated.
void percolate_up(IndexNode* Current, int btree_order, IndexNode* Right, IndexNode* Root)
{
if(Current->Parent == NULL)
{
IndexNode* UpperNode = new IndexNode;
UpperNode->AddChild(Current);
UpperNode->AddChild(Right);
Current->Parent = UpperNode;
Right->Parent = UpperNode; //This is defined inside an if statement
// in main yet this statement doesn't affect it
UpperNode->AddKey(Current->Keys[btree_order]);
Root = UpperNode;
}
else if(.......){
...
...
percolate_up(....);
}
}
int main(){
...
if(...){
IndexNode* RightNode = new IndexNode;
percolate_up(Current, btree_order, RightNode, Root);
//RightNode->Parent is still NULL here but Current->Parent is changed
//Also Root is unchanged, Why does this happen?
}

All objects created with "new" will exists after function return. So you should use it.

Related

Why Is My Binary Tree Overwriting The Leaves Of Its Root?

I've pinpointed my issue to this specific function, it's the helper function for my binary tree. Before this function call there is a node but instead of growing it seemingly just replaces that node. When I look at my code in my head it all makes sense but I can't figure out what I'm doing wrong.
Here is the function that calls add:
void BSTree::Insert(Client &newClient) {
if (isEmpty())
{
Node *newNode = new Node(newClient);
this->root = newNode;
}
else
add(this->root, newClient);
}
and here is my add() function:
BSTree::Node* BSTree::add(Node *node, Client &newClient) // helper function for Insert()
{
if (node == nullptr)
{
Node *newNode = new Node(newClient);
//node = newNode; // already tried adding this in
return newNode;
}
if (newClient.clientID < node->pClient->clientID)
return node->left = add(node->left, newClient); // already tried just returning add()
else
return node->right = add(node->right, newClient);
}
Since this is your question, I will explain what your code is doing. Imagine you have a mature binary tree already and you are adding a node to your tree. By the time you reach this line
return node->left = add(node->left, newClient);
Three separate instructions are carried out:
newClient is added to the left branch of node by add().
the left child of node is set to the return value of add().
the right hand side (RHS) of the assignment is returned by the parent function.
The issue is with number 2. If the tree you are adding to is mature already, changing left child of nodes as you're traversing the tree will cause the override effect that you're observing. In fact, the problem goes beyond overwriting leaves. Since you use the new keyword, the overwritten nodes still have allocated heap space, are never deleted and cause a memory leak.
Here are some thoughts to get you on the right direction:
Your insert() function ensures that the first time you call add(), you are not passing nullptr as the first argument. Take advantage of that and ensure nullptr is never passed into add() function by checking for nullptr before you do the recursive call. Change the return type of add() to void. You no longer need to check node is nullptr. Here's some pseudocode to guide you
void add(node, val)
if val < node.val
if node.left exists
add(node.left, val)
else
make a new object and set node.left to that object
else
if node.right exists
add(node.right, val)
else
make a new object and set node.right to that object
There is a problem with your logic. First of all, there is the insert() method which you should write like this for better understanding:
void BSTree::Insert(const Client &newClient) // use const to prevent modification
{
if (isEmpty()) { root = new Node(newClient); }
else { add(this->root, newClient); }
}
This way you are creating a new object at root directly with the help of 'root' pointer in BSTree.
Now, about the add() method. The 'node' you are passing as a parameter is a copy of the pointer variable, so the actual pointer value is not changed. See this:
BSTree::Node* BSTree::add(Node *node, Client &newClient) //logical error
You need to pass the Node* by reference like this using 'Node* &node':
BSTree::Node* BSTree::add(Node* &node, const Client &newClient)
Why is you binary tree overwriting the roots of its leaves? Answer:
Your recursive call with return statement is totally wrong.
return node->left = add(node->left, newClient);
The add(node->left, newClient) always returns the address of the leaves, and you are returning this value. It goes for recursive calls until it reaches the leaves place.
Conclusion: Since, there are a lot of bugs, I would suggest you re-write logic again carefully.
I hope this helps! :-)

pointer problems with function calls

I’m working on a beginner(!) exercise.
I am comfortable passing basic variables and also using &variable parameters so I can make changes to the variable that are not destroyed when returning. But am still learning pointers. I am working on the basic Mutant Bunny exercise (linked list practice).
In it I create a linked list by declaring Class Bunny. I set it up as you expect with a data section and a ‘next’ pointer for set up the linkage.
struct Bunny {
string name;
int age;
// more variables here
Bunny* next;
};
Everything works great when I call function to do things like create Bunnies using the function:
Bunny* add_node ( Bunny* in_root ){}
This sets up the node and returns it just like I want. I can also do things like call a function to modify the Bunny class like aging the bunnies.
void advanceAge ( Bunny* in_root ){}
I pass in the head and then I can modify the bunnies in the called function and it stays modified even when it goes back to main. For example I can use:
in_root->age ++;
in the called function and when I return to ‘main’ it is still changed. Basically I can use -> in any called function and it makes the change permanently. I think because the pointer is dereferenced(?) by the -> but still getting my head around it...
So far so good.
The problem comes up when I want call a function to delete the list. (Nuclear option… no more bunnies)
I can delete all the nodes in the called function… but it does not change the Bunny in ‘main’. For example… this does not permanently remove the node.
void DeathCheck(Bunny* in_root){
Bunny* prev_ptr;
prev_ptr = in_root;
if (prev_ptr == NULL){
cout << "No list to check age." << endl; return;
} else {
prev_ptr = NULL; // <- what could I code to have this stick? return;}
// rest of DeathCheck
I’m curious if there is a way to set the node to NULL in the called function and have it stick?
Since you're passing in_root by value, there's no way for it to modify the caller's variable. You could pass it by reference.
void DeathCheck(Bunny* &in_root) {
Bunny *prev_ptr = in_root;
...
in_root = nullptr;
return;
}
Currently, in DeathCheck(Bunny* in_root), there is no way that in_root can be changed, only the object it is pointing to can be changed. (See pass by reference and value with pointers). Based on this, you need to change the parameter to pass-by reference, eg by changing the signature of your function to this:
DeathCheck(Bunny* &in_root)
{
//...
}
This passes the Bunny by reference, meaning that it can now be reassigned to without a copy.

How do i delete a class node with pointer chidren

I am having errors deleting the private member class called tree2, I have tried to use "**", "&*", "*&" but I just keep getting error after error.
header file:
class tree1
{
private:
class tree2
{
tree2*child;
tree2**child2;
int data;
};
void clear( tree2** the_root);
tree2* root;
};
I am the one who has put the clear function there.So I go in the .cpp file and implement it this way:
void tree1::clear(tree2** TheRoot)
{
if(*TheRoot == NULL) { return; }
clear(&(*TheRoot->child1));
clear(&(*TheRoot->child2));
delete TheRoot;
TheRoot = NULL;
}
then in a function that used clear, i call it as clear(root) or clear(&root) or clear(*root) or clear(&*root).All combinations have failed, i keep getting erros. What is the right way to delete this class ?
As it seems you want your root-Pointer to be NULL after deletion. That is the reason why just passing tree2* as a parameter is not sufficient and the tree2** is necessary.
The line delete TheRoot; will not delete root, but a pointer to root (which was not allocated via new in your example, thus causing some hidden error. The same problem is in the next line. You can solve this by writing delete *TheRoot; *TheRoot = NULL;.
But since you are using C++, you can pass tree2*& like so:
void tree1::clear(tree2*& TheRoot)
{
if (TheRoot == NULL) { return; }
clear(TheRoot->child1);
clear(TheRoot->child2);
delete TheRoot;
TheRoot = NULL;
}
and call it like clear(root);
you need to call it with clear(&root) if you want to modify the value. In side, you do *root = null to clear it.
It is sufficient to use just tree2 and tree2* (pointer to a tree2 type) data types, do not use tree2** (pointer to a pointer of ..).
Do not expect the pointed by element to be NULL, but set the pointer value to NULL and just check the pointer values to decide if they point to allocated memory or not.

My C++ program crashes on this function?

I'm a beginner programmer(Just started) and I'm writing some code for a binary search tree for fun.
For some reason, whenever I call this append function my program crashes. It has to do with one of the two functions itself, not anything else in the header file or my source file which includes main(). By the way Leaf is just a struct with an int value, and two Leaf pointers named left and right.
This crashes with no output error.
Leaf* BinarySearchTree::GetLeaf(int x,Leaf*a)
{
int key = a->value;
cout <<key<<"\n";
if(x > key)
{
if(a->right == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->right = newleaf;
return newleaf;
}
else if (a->right != NULL)
{
return a->right;
}
}
else if(x< key)
{
if(a->left == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->left = newleaf;
return newleaf;
}
else if (a->left != NULL)
{
return a->left;
}
}
else if(x == key)
{
//tbc
}
}
void BinarySearchTree::Append(int x)
{
if(root != NULL)
{
Leaf* current = root;
while(current->value != x)
{
current = BinarySearchTree::GetLeaf(x,current);
cout<<"value: "<<
current->value;
}
}
else
{
cout <<" No ROOT!";return;
}
}
If you want to see my main (source) file, go here(Since I don't want to flood this post)
http://pastebin.com/vrh7KkMm
If you want to see the rest of the header file, where these two functions are located,
http://pastebin.com/ZGWewPdV
In your BinarySearchTree constuctor, you start accessing root without having allocated memory for it first. This may be your crash. Try adding
root = new Leaf()
at the start of the constructor.
Edit - More information:
C++ does not automatically set values for your member variables, you normally need to initialize them by hand. (c++11 does allow you to do it in the declaration). This means that any variable that you don't set to a value will have a garbage value in it. If you use this garbage value as a pointer, you will most likely get a crash.
In your case, one of the initial problems is that the LinkedList class did not initialize its root member variable in the constructor before starting to reference it.
BinarySearchTree has the same problem.
Learning to use the debugger is one of the best things you can do when learning to program. It lets you step through your code one line at a time and look at the value of each variable. This makes i easy to see where things aren't going as you planned. Which debugger you use depends on your platform.
If GetLeaf() is called with x == key the function returns neither nullptr nor a valid pointer. This is a potential crash source. You need to return something sensible in any case.
UPDATE: Don't forget to initialize the Leaf structure properly in its constructor (all three members).
UPDATE2: Also initialize your root properly. I would initialize it with nullptr and change the append function in a way that it creates the very first leave if root==nullptr.

Recursive data structure in c++

I'm implementing a recursive data structure in c++ using classes. I'm having some trouble implementing it particularly with the "this" pointer.
In one function, I need to modify the "this" pointer. However that is not allowed. How do I do it? I read somewhere that you will need to pass "this" pointer to that function to change it. However I'm not clear with that. Does that behave like python's "self"? An example would be great
EDIT:
void insert(int key)
{
if (head == NULL)
{
/* I need to insert in beginning of structure */
List* tmp;
tmp->key = key;
tmp->next = this;
this = tmp; /* This does not work */
}
}
Thank You!
You cannot modify the this pointer, given that it behaves as if declared T* const. What you could do is hold a pointer to your own type inside of the class, and modify that.
class foo
{
/* ... */
private:
foo* p; // this can be modified
};
You cannot modify this, period. You need to re-structure your program so that you don't need to do that.
The best way to insert the way you're trying to is to create a double linked list, not a single one (with only the next pointer). In other words, you should have a previous pointer that points to the previous node in the list to properly insert using the this pointer. Else you need to insert from the parent node of the this.
ie with a double linked list:
Node* tmp = new Node;
tmp->key = key;
this->previous->next = tmp;
tmp->previous = this->previous;
tmp->next = this;
this->previous = tmp;
Edit:
Don't forget that "this" is ""simply"" a memory address so what you want to change is what's contained in it.