Binary Search Tree deletion - c++

I am a beginner in programming and currently learning about bst. I have found several functions which delete bst, but they seemed to me overcomplexed. So i am interested if my own code cleans all the memory, every pointer and value of a binary search tree.
void deletebst (Node*& node)
{
if (node!=NULL)
{
deletebst (node->ldes); //deletes a left descendant recursively
deletebst (node->rdes); //same but with the right one
delete node; //deletes the value which a pointer 'node' points to
node=NULL; //sets a pointer 'node' to NULL, so deletes a pointer itself
}
}

As pointed out in the comments section, there's no need to set node = NULL, after it's been deleted. The rest of the code is fine. Cheers!

Related

optimized code for deleting a node in singly linked list

can this piece of code be used to delete a node at a specified position
void del(node *&head,int position)
{
int jump=0;
node *temp=head;
while(jump<position-1)
{
temp=temp->next;
jump++;
}
node *copy=temp->next;
temp->next=temp->next->next;
delete copy;
also what is the most efficient method to delete a node in a specific position?
can this piece of code be used to delete a node at a specified position
This is the correct algorithm for the most part. It doesn't handle deletion of position 0 correctly through so it cannot be used as such.
what is the most efficient method to delete a node in a specific position?
More efficient than this is to pass pointer to previous node as argument instead of pointer to head and position. But for given inputs, the algorithm that you've used is asymptotically optimal.

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! :-)

Binary search tree valgrind error "Invalid read of size 8"

I'm creating a recursive function for a binary search tree that removes the minimum node, which would be the leftmost node in the tree. I start at the root and traverse down from there. I'm trying to understand why I'm getting an invalid read of size 8 error. I'm pretty sure the current node I'm at will never be NULL and I created a conditional for if the tree is empty.
void removeMinimumValue()
{
removeMinimumValue(root);
}
void removeMinimumValue(BSTNode *node)
{
if(root==NULL)
exit(1);
else if (node->leftChild==NULL)
delete node;
else
removeMinimumValue(node->leftChild);
}
I suppose this happens during the second removal of the minimum value?
During the first removal, you delete the lowest node, but it's parent still has a reference to it (a "dangling pointer"). Next iteration, the function will try to read the deleted node.
I'd also like to add that if the lowest node has a right child, you have to add it as the left child,of it's parent node. Otherwise you're losing those nodes. You don't even have to check if this node has right children, because if it's NULL, you'd have to write NULL to the left child of the parent of the deleted node.
So change delete node; to
node->parent->leftChild = node->rightChild;
delete node;

Linked ArrayList Implementation

I am trying to implement a Linked ArrayList in C++ for instruction purposes, I've hit a snag though and I'm unsure how to unsnag it. My pointer array doesn't seem to be composed of pointers, but of actual objects.
Keeping my code as brief as possible.
//arraylist.h//
class classArrayList {
private:
class Node {
Node();
//accessors
};
Node* classArray;
public:
classArrayList();
};
//arraylist.cpp//
classArrayList::classArrayList() {
Node* node = new Node();
this->setHead(node);
this->setMaxSize(5);
classArray = new Node[5];
this->classArray[0] = *node;
this->setSize(1);
}
void classArrayList::deleteNode( int index ) {
Node* my_current = &this->classArray[index];
//blahblah
}
But when I go to delete a node, "my_current" doesn't link to whatever would be next or prev in this list. Trying to delete at position zero, no next.
So there's definately a node with data but it doesn't have its links, but checking the debugger my linked list is fine and works, so its whatever the array is pointing to that's screwing up.
So instead of pointing to the list, its pointing to unique instances, how can I fix this?
My code to add something new to the array is: this->classArray[some_index] = *new_node;
To clarify, I wanna be able to have an array that points sequencially to each object in my linked list. And then when I ask for one at any n in my arraylist, reference it to a pointer and then do thins to the object in my list through its position in the array, rather than increment through the list until I find the nth one I want.
Make your classArray a double pointer and create a Node pointer array. Node* classArray; Copy the address of head of your list to each array.
classArray = new Node*[5];
In your code by your statement this->classArray[0] = *node; you are not storing the address of the newly created, instead content of newly created node. And by deleting you are not removing the dynamically created list head.
For copying the address of newly created list you should use
this->classArray[0] = node;
The code works as it should. When you delete a node from your linked list, you delete the data under the pointer. As you set my_current to the address of the deleted node, you actually don't point to anything. The problem doesn't lie in the code, but in your understanding of the subject.
In order to really make a working linked list, every node should consist of a pointer to the next node. That way, when you delete a node, you'll first be able to retrieve the next node from the pointer, and set your my_current to a valid address.
In order to solve your problem, you should actually read a bit about the subject.
If you want to access the elements in "array style", overload the operator [].
Node& classArrayList::operator [](unsigned int index)
{
Node *node = head;
for(unsigned int i=0;i<index;i++)
if(node->next()) node = node->next();
else break;
return *node;
}

Given A pointer to a node, Delete that particular node

I have a pointer to a node, I want to delete that particular node from linked list.
The below logic works fine, But it fails if node to be deleted is Last node.
How to delete the last node?
void deleteNodWhosePointerIsGivene(node *pointerNode)
{
node *temp=pointerNode->next;
pointerNode->id=temp->id;
pointerNode->next=temp->next;
free(temp);
}
First of all you are not removing pointerNode from the list, you are removing the next node in the list. Secondly you are not checking if there is a next node or not.
Think about what you are trying to do.
You are trying to delete the next object in the list.
You are at the end of the list, therefore the temp pointer will be null.
You are then trying to get the next from null and also trying to free null.
Normally I would do something along the lines of.
DeleteObject(*obj)
Get Next Object
Get Prev Object
Set Prev->next = Next
Set Next->prev = Prev
Delete obj;
If I am understanding you comments above you are wanting to do a copy then your code should look like.
DeleteObject
Get Next Object
if (Next Object is not null)
This.Id == Next.Id
Free Next
else
Throw exception "Cannot delete last object in list"
There is no way to set the pointer in the second to last object in the list if you want to delete the last object in the list. The only way to do this is to either use a double-linked list, or iterate down the list looking for the pointer you wish to delete and keep track of the last object in the list.
You aren't deleting pointerNode in your code, You are deleting pointerNode->next.
Looking at your example of a single linked list. Let's say we have:
1->2->3->4->5
You pass in a pointerNode of "3". Your code then does the following:
1) Assigns pointerNode->Next to temp i.e. "4"
2) pointerNode->Next will be assigned temp->Next i.e. "5"
3) temp is freed i.e. "4"
so your list after this would be 1->2->3->5.
When you get to node "5" then you will get an access violation
1) pointerNode->next is assigned to temp i.e. NULL
2) pointerNode->Next will be assigned temp->Next i.e. access violation as you reference a NULL pointer.
A doubly linked list would be a better solution as to delete pointerNode you need to change the Next pointer of the previous node. Otherwise you'd have to scan the list first to find the node prior to pointerNode.
Here's the code which should work for a singularly linked list. Bear in mind this will be quite slow for large lists and I would second Andrew Norman's suggestion of using a doubly linked list.
Anyway.. here goes. In order for this to work you need to pass the root node of the list and beware that the address of this node may get changed if you try to delete it, hence I pass it as a pointer to a pointer.
void DeleteNode (Node **rootNode,Node *pointerNode)
{
Node *prevNode;
if (pointerNode == *rootNode) {
// Head node is being removed
*rootNode = pointerNode->Next;
} else {
// Find the previous node
for (prevNode = *rootNode; prevNode->Next != pointerNode;
prevNode = prevNode->Next) ;
prevNode->Next = pointerNode->Next;
}
// Free the node
free (pointerNode);
}
If you really need to delete the item associated with the node whose pointer you've got, then you have two options when it comes to the last node:
Iterate from the beginning of the list to find its predecessor (the next-to-last node), delete the last node and set it's predecessor's next to NULL.
Take the lazy approach - do not actually delete the node and only mark it as dead (e.g by setting its data to an impossible value.) Delete it later when you reach it from the predecessor (then also NULL-ing predecessor's next).
Both approaches have obvious drawbacks. This is why it is best to always have the predecessor when deleting a node from a linked list.
If you are able to have a reference to the previous node.
void deleteNodWhosePointerIsGivene(structNode* pCurrentNode, structNode* pPreviousNode)
{
// Not the Last Node ?
if(pCurrentNode->pNext)
pPreviousNode->pNext = pCurrentNode->pNext);
else
pPreviousNode->pNext = NULL;
delete pCurrentNode;
pCurrentNode = NULL;
}
Otherwise you will need to have a reference to the First Node of the List, and search for the previous.