I was trying to create a binary search tree with insert, search and remove functions but when run, the program throwing an error " Killed exit status 137 -- Out Of Resources --" ,
#include <vector>
using namespace std;
class BST
{
public:
int value;
BST *left;
BST *right;
BST(int val)
{
value = val;
left = nullptr;
right = nullptr;
}
BST& insert(int val)
{
BST *current = this;
while (current != nullptr)
{
if (val < current->value)
{
if (current->left == nullptr)
{
current->left = new BST(val);
break;
}
else
current = current->left;
}
if (val > current->value)
{
if (current->right == nullptr)
{
current->right = new BST(val);
break;
}
else
current = current->right;
}
}
return *this;
}
bool contains(int val)
{
BST *current = this;
while (current != nullptr)
{
if (val < current->value)
{
current = current->left;
}
else if (val > current->value)
{
current = current->right;
}
else if (val == current->value)
return true;
//else if(current ==nullptr)
//return false;
}
return false;
}
BST& remove(int val)
{
BST *current = this;
BST *parent = nullptr;
while (current != nullptr)
{
if (val < current->value)
{
parent = current;
current = current->left;
}
if (val > current->value)
{
parent = current;
current = current->right;
}
if (val == current->value)
{
if (current->left != nullptr && current->right != nullptr)
{
fnd(current->right);
}
else if (parent == nullptr)
{
if (current->left != nullptr)
{
current->value = current->left->value;
current->right = current->left->right;
current->left = current->left->left;
}
else if (current->right != nullptr)
{
current->value = current->right->value;
current->left = current->right->left;
current->right = current->right->right;
}
else
current = nullptr;
}
else if (parent->left == current)
{
if (current->left != nullptr)
{
parent->left = current->left;
}
else
{
parent->left = current->right;
}
}
else if (parent->right == current)
{
if (current->left != nullptr)
{
parent->right = current->left;
}
else
{
parent->right = current->right;
}
}
break;
}
}
return *this;
}
void fnd(BST *current)
{
BST *trav = current;
BST *parent;
while (trav->left != nullptr)
{
parent = trav;
trav = trav->left;
}
current->value = trav->value;
parent->left = nullptr;
}
};
Related
I am having trouble deleting a node from a binary search tree.
void BST::delete_node(Node* out)
{
Node* tmp;
Node* cur;
if(out->get_left() == NULL || out->get_right() == NULL) {
tmp = out;
}
else {
tmp = get_succ(out);
}
if(tmp->get_left() != NULL) {
cur = tmp->get_left();
}
else {
cur = tmp->get_right();
}
if(cur != NULL) {
cur->add_parent(tmp->get_parent());
}
if(tmp->get_parent() == NULL) {
root = cur;
}
else if(tmp == (tmp->get_parent())->get_left()) {
(tmp->get_parent())->add_left(cur);
}
else {
(tmp->get_parent())->add_right(cur);
}
if(tmp->get_key() != out->get_key()) {
out = nullptr;
}
}
What seems to be the problem here, that is causing nodes to not be deleted from the binary search tree.
I've run it many times. I tried fixing my deleteNode() and addNode(), but it did not work. The output showed me that it failed to add some valid entries in my list, which resulted in failing to delete these valid entries. Someone please help me find the errors... I think either my isEmpty() is wrong or the addNode got messed up.
// Add nodes and makes it work in any cases: backward/forward
bool LinkedList::addNode(int id, string str) {
bool result = false;
if (id >= 0 && !(idExists(id))) {
Node *current = head;
Node *temp = new Node;
temp->data.data = str;
temp->data.id = id;
temp->forward = NULL;
temp->back = NULL;
// Kinds of adding cases
if(head == NULL) { // Check if list is empty
addHead(temp, current);
result = true;
} else {
while(temp->data.id > current->data.id && current->forward != NULL) {
current = current->forward;
}
// Backward
if(current->back == NULL) {
if(temp->data.id > current->data.id) {
if(current->forward == NULL) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
} else {
addHead(temp, current);
}
result = true;
// Forward
}else if(current->forward == NULL) {
if (temp->data.id > current->data.id) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
result = true;
}else {
if(temp->data.id > current->data.id) {
addMiddle(temp, current);
result = true;
}
}
}
}
return result;
}
void LinkedList::addHead(Node *temp, Node *current) {
if (head != NULL){
temp->forward = current;
current->back = temp;
head = temp;
} else {
head = temp;
}
}
void LinkedList::addMiddle(Node *temp, Node *current) {
temp->forward = current;
temp->back = current->back;
current->back->forward = temp;
current->back = temp;
}
void LinkedList::addTail(Node *temp, Node *current) {
current->forward = temp;
temp->back = current;
}
// Delete list
bool LinkedList::deleteNode(int id){
bool result = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id && current->forward == NULL) {
if (current->back == NULL) { // Delete head
delete current;
head = NULL;
} else { // delete tail
deleteTail(current);
}
result = true;
} else if (current->data.id == id) {
if (current->back == NULL)
deleteHead(current);
else // delete middle
deleteMiddle(current);
result = true;
}
}
return result;
}
// Helper delete functions
void LinkedList::deleteHead(Node *current) {
head = current->forward;
head->back = NULL;
delete current;
}
void LinkedList::deleteMiddle(Node *current) {
current->back->forward = current->forward;
current->forward->back = current->back;
delete current;
}
void LinkedList::deleteTail(Node *current) {
current->back->forward = NULL;
delete current;
}
bool LinkedList::getNode(int id, Data *data) {
bool didGetNode = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
data->id = current->data.id;
data->data = current->data.data;
didGetNode = true;
}
return didGetNode;
}
// Check whether or not the id exists
bool LinkedList::idExists(int id){
bool exists = false;
if (head != NULL){
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id) {
exists = true;
}
}
return exists;
}
You probably want to be passing a pointer to a pointer (**) or a pointer to a reference (*&) in functions where you are wanting to make a change to what the address of the node is containing. I hope that this helps you visualize it.
For example:
struct Node { };
void setNull1(Node* temp)
{
temp = nullptr;
}
void setNull2(Node** temp)
{
(*temp) = nullptr;
}
void setNull3(Node*& temp)
{
temp = nullptr;
}
int main()
{
Node* tmp = new Node;
setNull1(tmp);
if (tmp == nullptr)
{
cout << "NULLPTR";
} // tmp is not nullptr
Node* tmp1 = new Node;
setNull2(&tmp1);
if (tmp1 == nullptr)
{
cout << "NULLPTR";
} // tmp1 is nullptr
Node* tmp2 = new Node;
setNull3(tmp2);
if (tmp2 == nullptr)
{
cout << "NULLPTR";
} // tmp2 is nullptr
}
You should also consider writing nullptr instead of NULL.
So I have my own implementation on BST. Now I need to implement remove_value function, which would remove a node with that value from my tree. I have this simple code:
void binary_tree::remove_value(int value)
{
if (!this->exists(value)) return; //if value doesnt exist - return
nodeBST* current = root;
nodeBST* prev = nullptr;
bool left = true;
while (true)
{
if (current->value == value) // when we find it
{
if (current->right == nullptr && current->left == nullptr) // 0 children
{
delete current;
this->n--;
if (left) prev->left = nullptr;
else prev->right = nullptr;
//even tried delete current here
return;
}
else if (current->right == nullptr && current->left != nullptr) // 1 lewe dziecko
{
if (left) prev->left == current->left;
else prev->right == current->left;
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left == nullptr) // 1 prawe dziecko dziecko
{
if (left) prev->left == current->right;
else prev->right == current->right;
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left != nullptr) // dwoje dzieci
{
nodeBST* tempNode = findMin(current);
current->value = tempNode->value;
remove_node(current, prev, left);
}
}
else if (current->value > value)
{
prev = current;
left = true;
current = current->left;
}
else
{
prev = current;
left = false;
current = current->right;
}
}
}
I know its kinda mess, so I will tell you what it does. The bottom part is looping through the tree. If the the value we are searching is bigger that the current node value, the previous becomes current, current becomes current->right and left = false. The opposite, when its smaller. Now look that the first if after current->value == value - this is the code which should execute for 0 children. Now, it does delete the current node, but I have a problem.
I have a printing function, which takes a whole tree, and prints it. And it crashes with some pointer error. I checked. When I delete current it sets prev->left or prev->right (depending on left value) to like 0xdddddddd, no matter if I delete after assigning prev-> or before. I even tried to delete prev->right/left and then assign nullptr but still the same happens. How can I make it delete the node, but still be able to assign nullptr to right or left property of prev node?
#Edit:
This code fails on line with print(:
void binary_tree::print(std::string sp, std::string sn, nodeBST* v)
{
if (this->is_empty()) return;
std::string s;
if (v)
{
s = sp;
if (sn == cr) s[s.length() - 2] = ' ';
print(s + cp, cr, v->right);
s = s.substr(0, sp.length() - 2);
std::cout << s << sn << v->value << std::endl;
s = sp;
if (sn == cl) s[s.length() - 2] = ' ';
print(s + cp, cl, v->left);
}
}
The exception is something like (I am translating from my language) that there was unwanted read from memory, and that the v was 0xddddd
So there was a bug inside if (current->right == nullptr && current->left == nullptr). This code is working:
void binary_tree::remove_value(int value)
{
if (!this->exists(value)) return; //if value doesnt exist - return
nodeBST* current = root;
nodeBST* prev = nullptr;
bool left = true;
while (true)
{
if (current->value == value) // when we find it
{
if (current->right == nullptr && current->left == nullptr) // 0 children
{
delete current;
this->n--;
if(prev!=nullptr) {
if (left) prev->left = nullptr;
else prev->right = nullptr;
}
//even tried delete current here
return;
}
else if (current->right == nullptr && current->left != nullptr) // 1 lewe dziecko
{
if(prev!=nullptr) {
if (left) prev->left == current->left;
else prev->right == current->left;}
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left == nullptr) // 1 prawe dziecko dziecko
{
if(prev!=nullptr) {
if (left) prev->left == current->right;
else prev->right == current->right;}
delete current;
this->n--;
return;
}
else if (current->right != nullptr && current->left != nullptr) // dwoje dzieci
{
nodeBST* tempNode = findMin(current);
current->value = tempNode->value;
remove_node(current, prev, left);
}
}
else if (current->value > value)
{
prev = current;
left = true;
current = current->left;
}
else
{
prev = current;
left = false;
current = current->right;
}
}
}
I've got a non-recursive pseudocode for deleting a node (without 2 children case at the moment), which I have to implement. Everything seems to be OK, except the situation when I want to delete a root.
The pseudocode:
delete(root, key)
{
parent = NULL;
p = root; //p - node to delete
while( (p != NULL) && (key != p->data) )
{
parent = p;
if( p->data < key ) p = p->right;
else p = p->left;
}
if( p == NULL ) return;
if( (p->right == NULL) && (p->left == NULL) ) // deleted node p is a leaf
{
if(p == root)
{
root = NULL; // deleted leaf is a root
return;
}
if( parent->right == p) parent->right = NULL;
else parent->left = NULL;
return;
}
if( p->right == NULL ) // p node to delete has only left subtree
{
if( parent->right == p ) parent->right = p->left;
else parent->left = p->left;
return;
}
if( p->left == NULL ) // p node to delete has only right subtree
{
if( parent->right == p ) parent->right = p->right;
else parent->left = p->right;
return;
}
}
And here is my implementation:
struct BstNode
{
int data;
BstNode *left, *right;
};
void Remove(BstNode **root, int key)
{
BstNode **parent, ***p;
parent=NULL;
p=&root;
while((**p!=NULL) && (key!=(**p)->data))
{
parent=&(**p);
if((**p)->data < key) *p=&(**p)->right;
else *p=&(**p)->left;
}
if((**p)==NULL)
{
cout << "no such element! " <<endl;
return;
}
if(((**p)->right)==NULL && (**p)->left==NULL)
{
if((**p)==*root)
{
*root=NULL;
return;
}
if((*parent)->right==(**p))
(*parent)->right = NULL;
else (*parent)->left = NULL;
return;
}
if(((**p)->right)==NULL )
{
if((*parent)->right== (**p))
(*parent)->right = (**p)->left;
else
(*parent)->left = (**p)->left;
return;
}
if(((**p)->left)==NULL )
{
if((*parent)->right==(**p))
(*parent)->right = (**p)->right;
else
(*parent)->left = (**p)->right;
return;
}
}
int main()
{
BstNode* root = NULL;
Insert(&root,2);
/* ... */
Remove(&root,2);
}
I believe that there's something wrong with "parent", because root has no parent. However, I have no idea how to find a way round this problem.
I have a very frustrated situation with my BST code:
vector<int> order;
BinarySearchTree tree;
for (int i=0; i<1000; ++i) {
int j = rand()%1000;
order.push_back(j);
}
for (int i = 0; i < 1000; ++i) {
tree.insert(order[i]);
}
while(!tree.isEmpty()) {
cout << tree.min() << endl;
tree.remove(tree.min());
}
the code is working perfectly fine with small number of i, say 10, or 100. However, it is stop working when i is 1000.
the insert function is as follows
void BinarySearchTree::insert(int d)
{
tree_node* t = new tree_node;
tree_node* parent;
t->data = d;
t->left = NULL;
t->right = NULL;
parent = NULL;
// is this a new tree?
if(isEmpty()) root = t;
else
{
//Note: ALL insertions are as leaf nodes
tree_node* curr;
curr = root;
// Find the Node's parent
while(curr)
{
parent = curr;
if(t->data > curr->data) curr = curr->right;
else curr = curr->left;
}
if(t->data <= parent->data)
parent->left = t;
else
parent->right = t;
}
}
In response to the comments, i am going to post all the code. :)
void BinarySearchTree::remove(int d)
{
//Locate the element
bool found = false;
if(isEmpty())
{
cout<<" This Tree is empty! "<<endl;
return;
}
tree_node* curr;
tree_node* parent;
curr = root;
//parent = root;
while(curr != NULL)
{
if(curr->data == d)
{
found = true;
break;
}
else
{
parent = curr;
if(d>curr->data) curr = curr->right;
else curr = curr->left;
}
}
if(!found)
{
cout<<" Data not found! "<<endl;
return;
}
// 3 cases :
// 1. We're removing a leaf node
// 2. We're removing a node with a single child
// 3. we're removing a node with 2 children
// Node with single child
if((curr->left == NULL && curr->right != NULL)|| (curr->left != NULL
&& curr->right == NULL))
{
if(curr->left == NULL && curr->right != NULL)
{
if (curr == root) {
root = curr->right;
delete curr;
}
else {
if(parent->left == curr)
{
parent->left = curr->right;
delete curr;
}
else
{
parent->right = curr->right;
delete curr;
}
}
}
else // left child present, no right child
{
if (curr==root) {
root = curr->left;
delete curr;
}
else {
if(parent->left == curr)
{
parent->left = curr->left;
delete curr;
}
else
{
parent->right = curr->left;
delete curr;
}
}
}
return;
}
//We're looking at a leaf node
if( curr->left == NULL && curr->right == NULL)
{
if (curr == root) {
root = NULL;
delete curr;
return;
}
else {
if(parent->left == curr) parent->left = NULL;
else parent->right = NULL;
delete curr;
return;
}
}
//Node with 2 children
// replace node with smallest value in right subtree
if (curr->left != NULL && curr->right != NULL)
{
tree_node* chkr;
chkr = curr->right;
if((chkr->left == NULL) && (chkr->right == NULL))
{
curr = chkr;
delete chkr;
curr->right = NULL;
}
else // right child has children
{
//if the node's right child has a left child
// Move all the way down left to locate smallest element
if((curr->right)->left != NULL)
{
tree_node* lcurr;
tree_node* lcurrp;
lcurrp = curr->right;
lcurr = (curr->right)->left;
while(lcurr->left != NULL)
{
lcurrp = lcurr;
lcurr = lcurr->left;
}
curr->data = lcurr->data;
delete lcurr;
lcurrp->left = NULL;
}
else
{
tree_node* tmp;
tmp = curr->right;
curr->data = tmp->data;
curr->right = tmp->right;
delete tmp;
}
}
return;
}
}
and the min() function
int BinarySearchTree::min()
{
tree_node *p=root;
while (p->left != NULL)
p=p->left;
return (p->data);
}
Looks like the last four lines have negated logic of the for loop.
The for loop says:
new val is larger go right else left.
The tree placement says:
new val is larger place left else place right.
Also I don't see your remove code, but the it may be affected by the wrong ordering.
Also try initializing rand before using it:
srand (time(NULL));
You need to improve on your random function. Try using int j = rand() instead.
EDIT: you have duplicate minimum values. With the code below you remove the top most node with minimum value.
while(curr != NULL)
{
if(curr->data == d)
{
found = true;
break;
}
else
{
parent = curr;
if(d>curr->data) curr = curr->right;
else curr = curr->left;
}
}
try the following code instead.
tree_node* left_most_duplicate;
while (curr != NULL)
{
if (d>curr->data) curr = curr->right;
else curr = curr->left;
if (curr->data == d)
{
parent = curr;
left_most_duplicate = curr;
found = true;
break;
}
}
curr = left_most_duplicate;