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.
Related
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);
}
}
}
I have a class that is a tree that is made up of nodes that have parent, leftChild, and rightSibling pointers. My intent was to delete the tree from the bottom to the top. With the way I have it set up currently, the nodes don't get "deleted" because the nodes that point to them are still pointing to that location, which should be nothing which causes an error.
Any help would be greatly appreciated. I've looked around but I haven't found a situation that is similar to mine.
OrgTree::~OrgTree()
{
TreeNode * curr = root;
while (curr->leftChild != nullptr)
{
if (curr->leftChild != nullptr)
{
curr = curr->leftChild;
}
}
while (root != nullptr)
{
if ((curr == root) && (curr->leftChild == nullptr))
{
delete(curr);
}
else
{
if (curr->leftChild == nullptr)
{
curr = curr->parent;
}
TreeNode * temp = curr->leftChild;
TreeNode * prev = curr;
while (temp->rightSibling != nullptr)
{
prev = temp;
temp = temp->rightSibling;
if (temp->rightSibling == nullptr)
{
prev->rightSibling = nullptr;
}
}
while (temp->leftChild != nullptr)
{
prev = temp;
temp = temp->leftChild;
if (temp->leftChild == nullptr)
{
prev->leftChild = nullptr;
}
}
delete(temp);
}
}
}
Ok, so... Your algorithm looks like:
Travel to deepest, left-most node.
Move up (1) to parent
Travel to right-most sibling of that node AND Unlink that node from prev
Travel to Deepest, left-most node of that node AND unlink that node from prev
delete whatever node you land on
My first thought is to use an std::vector<TreeNode*> when allocating the nodes and just deleting the nodes from the list. If I knew how many nodes I needed before constructing the tree, I might even be tempted to use std::vector<TreeNode> and hand out pointers like &myVector[mCursor++].
But, if we were going to go with the fully dynamic route and avoid pre-steps to track nodes as they are allocated, then what you are trying to do is called Post Order Traversal. There are several algorithms for post-order traversal of a binary tree, including ones without recursion. Here's one that uses a stack (although you should use std::stack<TreeNode*>).
Here's the recursive code Source:
/* Given a binary tree, delete its nodes according to the
"bottom-up" postorder traversal. */
static void deletePostorder(TreeNode* node)
{
if (node == NULL)
return;
// first recur on left subtree
deletePostorder(node->leftChild);
// then recur on right subtree
deletePostorder(node->rightSibling);
// now deal with the node
delete node;
}
OrgTree::~OrgTree()
{
deletePostorder(root);
}
Do you have control over TreeNode?
If so, you can make the TreeNode destructor delete their left and right child and your top level destructor is just
OrgTree::~OrgTree() {
delete(root);
}
So I am writing a BST node removal function, but I cannot figure out a problem:
I have this node-data structure:
struct webentry
{
char * topic;
char * keyword;
char * url;
char * summary;
char * review;
int rating;
};
The problem occurs at the point where the node has a two children and its right child has a left child (meaning I need to find the inorder successor and replace it with):
else if ((root->right != NULL) && (root->left !=NULL) && (root->right->left !=NULL))
{
node*tempr = root->right;
node*templ = root->left;
delete root->data.topic;
delete root->data.keyword;
delete root->data.url;
delete root->data.summary;
delete root->data.review;
delete root;
root = findis(tempr);
root->right = tempr;
root->left = templ;
return 1;
}
I wrote a findis function to deal with the inorder successor situation:
node* program4::findis(node* &root)
{
/* cout to figure out what's going on
cout<<"Topic: "<<root->data.topic<<endl; Finds it here
cout<<"Keyword: "<<root->data.keyword<<endl; Finds it here
*/
if ((root->left==NULL) && (root->right ==NULL))
{
node*temp = root;
delete root;
root = NULL;
/*
cout<<"Topic: "<<temp->data.topic<<endl; Empty
cout<<"Keyword: "<<temp->data.keyword<<endl; Finds
*/
return temp;
}
else if ((root->left == NULL) && (root->right != NULL))
{
node*temp= root;
node*tempn = root->right;
delete root;
root = tempn;
/*
cout<<"Topic: "<<root->data.topic<<endl;
cout<<"Keyword: "<<root->data.keyword<<endl;
*/
return temp;
}
else
{
return findis(root->left);
}
The problem is: When the node inorder successor returns, topic part becomes NULL, everything else stays the same. I have used GDB to figure out where it deletes the contents of topic, and it is right where I marked, right after the if condition meets and deletes the root in the findis function. It doesn't delete any other data of the the node, I don't know why it even deletes it. Can anyone see what is happening here?
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.
I have a linked list with a c-style ctor and dtor.
I just got too frustrated when this if statement decided not to test true, putting me in
an infinite loop. I dont understand why it will never test true.
I am trying to delete a node (the address of a class object) from my LinkedList.
Maybe someone could help me out?
Node *Current = first_; // I want this to be my only Node Ptr Varaible Declaration.
if ( NULL == first_ )
std::cout << "Cannot delete from an empty list: \n";
while ( Current != NULL )
{
if ( first_->data_ == node->data_ )
{
//check to see if we are deleteing the head.
first_ = first_->next_;
--listLen_;
delete Current;
std::cout << "Head Deleted!\n";
}
if ( Current->data_ == node->data_ ) // FOR SOME REASON this is never true?
{
--listLen_;
node->data_ = NULL;
Current = Current->next_;
node->data_ = Current;
}
else // we must not of found it. // else should match previous i
{
Current->prev_ = Current;// since we are not deleting the first node we are OK here.
Current = first_->next_;
if ( Current->next_ == NULL ) // see if we are at the end of the list.
{
first_ = NULL;
last_ = Current->prev_;
}
}
}
return;
This should really be rewritten, since it has too many problems...also why not use a STL container? I assume this is a homework question.
The answer to the infinite loop is the else case that increments to the next node:
Current = first_->next_;
This will make you loop forever if the data is not found in in the first two nodes...since you will set the next test to the first's next node always and it will never set the current to NULL provided there are more than 2 nodes in the list.
Keep your loops small, it easier to figure out what went wrong. Assuming your data compare makes sense, look at this the following:
curr = first_;
while( curr && (curr->data_ != node->data_) ) {
curr = curr->next_;
}
if (!curr) return // didnt find it, nothing to remove
if ( curr == first_ )
first_ = curr->next_
else
curr->prev_->next_ = curr->next_
curr->next_->prev_ = curr->prev_ // always fix next's prev
delete curr
I'm not entirely sure what you're trying to accomplish, but I'm certain you're doing it wrong. If you're merely trying to remove an element from a doubly-linked list that matches node->data_, it's as easy as this:
Node *Current = first_;
while (Current != NULL)
{
if (Current->data_ == node->_data)
{
//If Current isn't the head of the list, set prev to next
if (Current != first_)
Current->prev_->next_ = Current->next_
else
{
first_ = Current->next_;
if (first_ != NULL)
first_->prev_ = NULL;
}
//If Current isn't the tail of the list, set next to prev
if (Current->next_ != NULL)
Current->next_->prev_ = Current->prev_
else if (Current->prev_ != NULL)
Current->prev_->next_ = NULL;
delete Current;
Current = NULL;
}
else
{
Current = Current->next_;
}
}
return;
You don't show where node comes from or how data_ is defined, but if it is a pointer type, you probably need to compare the contents, not the addresses.
Assuming that data_ is a pointer to something and what it points to has operator== defined or is a built in type and it has the value you are looking for then you can do this instead:
if ( *Current->data_ == *node->data_ )
if first_->data_ == node->data_ ever evaluates to true then the second if statement will always evaluates to true then the second if condition will always evaluate to false Current->data_ == node->data_ because on the first iteration first_ == Current and you delete Current without ever updating it
To delete a node from a linked list you seem to be doing way too much work.
Not really an answer here for the actual question but a suggestion.I would never iterate through a linked list to delete an entry in the list. Each entry should have a valid next and previous pointer and when you go to delete an entry from the list you just make the previous record point to the next one and vice versa to remove yourself from the list. An empty list should have a head record and a tail record that just point to each other and all valid entries are inserted in between.
Delete a node with value passed.
void deleteBegin()
{
Node* temp =Head;
if(temp==NULL)
return;
Head=Head->next;
free(temp);
}
void deleteMiddle(int _data)
{
Node* curr = Head;
Node* prev = Head;
if(curr==NULL)
return;
if(curr->next==NULL)
{
deleteBegin();
return;
}
while(curr->next!=NULL && curr->data!=_data)
{
prev=curr;
curr=curr->next;
}
if(curr->data == _data)
{
if(prev==curr)
{
deleteBegin();
return;
}
prev->next = curr->next;
free(curr);
}
else
{
cout<<"Element Not Found\n";
return;
}
}