Binary Search Tree deletion of target node has two children - c++

Here is my code, the replacement was correct (replaced the target node with the largest node in the left sub-tree), but after the replacement, both of the left and right sub-trees are gone.
Here is my code:
else if (temp->left != NULL && temp->right != NULL)
{
minLeaf = temp->left;
minLeafMa = temp->left;
parentRight = parent->right;
while (minLeaf->right != NULL)
{
minLeafMa = minLeaf;
minLeaf = minLeaf->right;
}
if (parent->left == temp)
{
parent->left = minLeaf;
minLeafMa->right = NULL;
}
else if (parent->right == temp)
{
parent->right = minLeaf;
minLeafMa->right = NULL;
}
}

The correct way of deleting a node x with 2 children is finding the inorder successor or predecessor of x, replacing x's value with the predecessor's or successor's values and call delete on either of them(whichever you used).
You are using the predecessor here. You are doing
parent->left = minLeaf;
which points the left of parent to the leaf node(the predecessor node) resulting in all the nodes in between to be gone. Instead what you should do is
temp->data = minLeaf->data;
and recursively call delete on minLeaf.

Related

asymptotic complexity of post traversal + deletion

I wanna ask what the time complexity of post traversal in BST if I removed some specific nodes in it while doing the traversal, for example: A dictionary BST that has a word, and a meaning. We want to delete all words with data equal to an empty string, the tree could be unbalanced.
this is my algorithim:
void delete_nodes(Node*& node) {
if (node == nullptr) {
return;
}
delete_nodes(node->left);
delete_nodes(node->right);
if (node->data == "") {
// Node to be deleted has 0 or 1 child
if (node->left == nullptr) {
Node* temp = node->right;
delete node;
node = temp;
} else if (node->right == nullptr) {
Node* temp = node->left;
delete node;
node = temp;
} else {
// Node to be deleted has 2 children
// Swap the values of the node and the leftmost node in its right subtree
Node* temp = node->right;
while (temp->left != nullptr) {
temp = temp->left;
}
node->data = temp->data;
// Set the data of the leftmost node in the right subtree to an empty string
temp->data = "";
// Delete the leftmost node in the right subtree
delete_nodes(node->right);
}
}
}

c++ replace values in linked list by changing pointers

Having a problem with linked list. Need to create a method, which will replace data in list, by not creating a new element but by changing pointers. For now I have such method:
void replaceValues(Node* head, int indexOne, int indexTwo)
{
Node* temporaryOne = NULL;
Node* temporaryTwo = NULL;
Node* temp = NULL;
Node* current = head;
int count = 0;
while (current != NULL) {
if (count == indexOne)
{
temporaryOne = current;
}
else if (count == indexTwo)
{
temporaryTwo = current;
}
count++;
current = current->next;
}
current = head;
count = 0;
while (current != NULL) {
if (count == indexOne)
{
head = temporaryTwo;
}
else if (count == indexTwo)
{
head = temporaryOne;
}
count++;
current = current->next;
}
}
I am sure, that exists a more simpler way, how to do it, but I don't fully understand, how it works...
Thanks in advance for help.
I assume that with "replace" you actually mean "swap"/"exchange".
Some issues:
The argument head should be passed by reference, as one of the nodes to swap may actually be that head node, and then head should refer to the other node after the function has done its job.
The node before temporaryOne will need its next pointer to change, so you should stop your loops one step earlier in order to have access to that node and do that.
In some cases head may need to change, but this is certainly not always the case, so doing head = temporaryOne or head = temporaryTwo is certainly not right. In most cases you'll need to link to the swapped node from the preceding node (see previous point).
The next pointer of the node that is swapped will also need to change, as the node that follows it will be a different one than before.
As mentioned already in comments, it is advised to split the task into removals and insertions, as the fiddling with next pointers can get confusing when you try to cover all possible cases, notably making the distinction between the case where the two nodes are adjacent and when they are not.
Here are some functions that split the work into removal, insertion and finally exchanging nodes:
Node* removeNode(Node* &head, int index) {
// If index is out of range, no node is removed, and function returns nullptr
// Otherwise the extracted node is returned.
if (head == nullptr || index < 0) return nullptr;
Node* current = head;
if (index == 0) {
head = head->next;
current->next = nullptr;
return current;
}
while (--index > 0) {
current = current->next;
if (current == nullptr) return nullptr;
}
Node* temp = current->next;
if (temp != nullptr) {
current->next = temp->next;
temp->next = nullptr;
}
return temp;
}
void insertNode(Node* &head, Node* node, int index) {
// If index is too large, node is inserted at the end of the list
// If index is negative, node is inserted at the head of the list
if (index <= 0 || head == nullptr) {
node->next = head;
head = node;
return;
}
Node* current = head;
while (--index > 0 && current->next != nullptr) {
current = current->next;
}
node->next = current->next;
current->next = node;
}
bool exchangeNodes(Node* &head, int indexOne, int indexTwo)
{
// Returns true when successful, false when at least one index
// was out of range, or the two indexes were the same
if (head == NULL || head->next == NULL || indexOne == indexTwo || indexOne < 0) return false;
// To ensure the right order of operations, require the first index is the lesser:
if (indexOne > indexTwo) return exchangeNodes(head, indexTwo, indexOne);
Node* two = removeNode(head, indexTwo);
if (two == nullptr) return false; // out of range
Node* one = removeNode(head, indexOne);
insertNode(head, two, indexOne);
insertNode(head, one, indexTwo);
return true;
}

C++ trouble deleting nodes with only one child in BST

I'm having difficulty deleting a node in my binary search tree. The delete function is part of my Node class, and my findMin function is as well. Below is my delete function...
/**********************************************
* Delete
**********************************************/
node* node::Delete(node *root, string stuff)
{
//node *temp;
if (root == NULL) // Searches for value in tree
return NULL;
if (stuff < root->val) // String is in left subtree
root->left = Delete(root->left, stuff);
else if (stuff > root->val) // String is in right subtree
root->right = Delete(root->right, stuff);
else
{ // No children
if ((root->left == NULL) && (root->right == NULL))
{
delete(root);
root = NULL;
}
else if ((root->right == NULL) && (root->left != NULL)) // One left child node
{
node *temp = root;
root = root->left;
delete temp;
temp = NULL;
}
else if ((root->left == NULL) && (root->right!= NULL)) // One right child node
{
node *temp = root;
root = root->right;
delete temp;
temp = NULL;
}
else // Two children
{
node *temp = findMin(root->right); // Finds smallest value in right subtree
root->val = temp->val;
root->right = Delete(root->right, temp->val);
}
}
return root;
}
Below is my Destructor, which is giving me a SIGABRT (I'm using Xcode)
/**********************************************
* Destructor
**********************************************/
node::~node()
{
if (left != NULL) delete left;
if (right != NULL) delete right;
}
What my code is actually doing is not only deleting the node I intend to delete, but its child node. What could I be doing wrong? Is it an error with memory allocation? Is it an error with how I set the value to the child node?
You need to null your pointers to left and right before deleting a node.
You call:
node *temp = root;
root = root->left;
delete temp;
temp = NULL;
When you "delete temp" you are deleting a node which still points to root->left and root->right and your destructor insures they are also removed. You should instead do something like this:
node *temp = root;
root = root->left;
temp->left = NULL;
temp->right = NULL;
delete temp;
temp = NULL;
Also in your destructor you don't need to check if they are equal to null since delete already preforms this check.

Building Huffman encoding tree from ordered list

I am building a huffman encoding tree from an ordered linked list (sorted by frequency of letters) that begins with the lowest frequency. After creating the tree, I traversed it and it appears that the tree was implemented incorrectly. When I traversed the tree, some of the nodes from the ordered linked list appeared to have be left out. (I don't think it was because my traversal is wrong.) Here is my code for the tree:
//My class for the nodes in the ordered linked list that will be converted to a tree
class fList{
public:
fList();
int frequency;
char letter;
fList* next;
fList* left;
fList* right;
};
fList::fList(){
frequency = 0;
letter = NULL;
next = NULL;
left = NULL;
right = NULL;
}
fList* head = NULL;
.
.
.
.
.
//Create the huffman encoding tree from the linked list stored in head
while(head->next != NULL){
fList *tree = new fList();
fList *temp = new fList();
fList *trail = new fList();
/* Take the first two frequency numbers, add them, create a new node
* with the total frequency number and have new node point to the first
* two nodes (right child and left child)
*/
total = (head->frequency + head->next->frequency);
tree->frequency = total;
//Set a new head node
tree->left = head;
tree->right = head->next;
head = head->next->next;
tree->left->next = NULL;
tree->right->next = NULL;
//place tree node in its correct place in sorted list
temp = head;
trail = temp;
if(head->frequency >= tree->frequency){
tree->next = head;
head = tree;
}
else if(temp->next != NULL){
while(temp != NULL){
if(temp->frequency >= tree->frequency){
tree->next = temp;
trail->next = tree;
break;
}
else{
trail = temp;
temp = temp->next;
}
}//while
//insert at the end of list
if(temp == NULL){
temp = tree->next;
trail->next = tree;
}
}//else if !=NULL
else if(head == NULL || head->next == NULL) head = tree;
}
At the end of the piece of code you posted, in the line
else if(temp->next = NULL && head != NULL) head = tree;
you inadvertently truncate the tree by setting temp->next = NULL where you probably meant to ask whether temp->next == NULL. This may be why some of the entries (the ones linked to by temp) are left out from the final result.

Binary tree delete

I am trying to finish the delete function
Here is the pseudo code, notice the end.
I don't know if the pseudo code is wrong though.
Here is how I interpreted it:
Node* minNode = Minimum(toDelete->right);
int tmp = 0;
tmp = minNode->val;
// delete(&tmp);
free(minNode);
minNode=NULL;
toDelete->val=tmp;
Except once it deletes it, it starts filling a trillion zeroes when printing.
Is what I am doing make any sense?
The rest of the code I have is right, or I think so anyway. It only screws up in this scenario.
Here's the minimum function as well
Node* BST::Minimum(Node *curr) {
// if (curr->left != NULL) {
// return(Minimum(curr->left));
// }
// return curr;
Node* node = curr;
while (node->left != NULL) {
node = node->left;
}
return node;
}
You want to first of all search the tree so see if the node you want to delete is there.
if it is there, you want to check for three casing:
1: when you want to delete a Node that have no child.
: in this case you just delete the said node as it does not have any child.
2: when you want to delete a node that has either left of right child
: in this case you set the left or right child to the parent of the node you want to delete
3: when you want to delete a node with two children
: in this case you have to find the successor of the node you are to delete, then swap the successor with the delete node.
public Boolean delete(int key)
{
Node current = root;
Node parent = root;
//search for node here
while(current->key != key)
{
parent = current; //save the parent the nodes as you loop through it
if(key < current->key)
current = current->left
else
current = current->right
//if you do not find the key return false
if(current==null)
return false;
}
//case 1 start here:
//check if the said node has no child. in this case we are looking at current
if(current->left ==null && current->right == null)
{
//check if the node you want to delete is the root
if(current == root)
root = current
else
{
if(parent.key > current->key)
parent-left = null;
else
parent->right = null;
}
}//case 2 here:
//check to see if the node has either left or right child
else if(statement for checking left here)
{
//check for the case where your delete a root
//set the the parent of the current->left to be current->parent
}
else if(statement for checking right here)
{
//check for the case where your delete a root
//set the the parent of the current->right to be current->parent
}
else
{
//create a node successor and give it the successor you found
Node successor = findSuccessor(Node NodeToDel);
//check for root being the node you want to delete
if(root == successor)
root = successor;
else
{
//navigate left, set parent->left = successor
//navigate right, set parent->right = successor
//with the nature of the findSuccessor() algorithm i have,
//i will have to code one more line:
// give succeccor->left = current->left;
}
}
}
I hope this will help in some way.