I have a method to insert a node into a binary tree, which uses a pointer to pointer to correctly allocate new nodes in the tree.
As I'm using C++, I think that it's possible to change this pointer to pointer to a reference to pointer, leading to cleaner and C++-ish code. But how to do this and keep the allocation correct?
bool insert(T value) {
node** buff = &root;
while ((*buff) != NULL) {
if (value == (*buff)->value) {
return false;
} else if (value < (*buff)->value) {
buff = &(*buff)->left;
} else {
buff = &(*buff)->right;
}
}
*buff = new node(value);
return true;
}
not tested, but this is the idea: you insert when you are in parent, not when you descended into null:
bool insert(T value) {
if (root == nullptr) {
root = new node(value);
return true;
}
node* buff = root;
while(buff->value != value) {
if (value < buff->value) {
if(buff->left == nullptr {
buff->left = new node(value);
return true;
}
buff = buff->left;
} else {
if (buff->right == nullptr) {
buff->right = new node(value);
return true;
}
buff = buff->right;
}
}
return false;
}
how i would write it:
// returns the node under which the insertion must be done
// or nullptr if the value already exists in the tree
// prereq: tree must be not empty
node* findParentInsertionPoint(T value) {
if (root == nullptr) {
throw std::logic_erro("");
}
node* n = root;
while(n->value != value) {
if (value < n->value) {
if(n->left == nullptr {
return buff;
}
n= n->left;
} else {
if (n->right == nullptr) {
return n;
}
n= n->right;
}
}
return nullptr;
}
// inserts a leaf as child of parent
// prereq: parent must be not null
// the corresponding child must be null;
void insertLeafAt(T value, node * parent) {
if (parent == nullptr) {
throw std::logic_error("");
}
if (value < parent->value) {
parent->left = new node(value);
} else {
parent->right = new node(value);
}
}
bool insert(T value) {
if (root == nullptr) {
root = new node(value);
return true;
}
node* parent = findParentInsertionPoint(value);
if (parent == nulptr) {
return false;
}
insertLeafAt(T value, parent);
return true;
}
You cannot reassign a reference, so due to buff = &(*buff)->left;,
you can't change node** buff = &root; to node*& buff = root; (and replacing (*buff) by buff).
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.
This genuinely has me stumped. I have a binary search tree of citys that is ordered by the city name. A city also contains the population and GPS coordinates. I want to be able to remove nodes from the tree by City name or city coordinates. I have the delete by name working fine but the GPS coordinates does not work.
When I remove a node by GPS I get a stack-overflow when I try to print the binary tree. Below is some of my code. I cannot understand how it will work fine if I delete by name but not if I delete by coordinates as I am using the same delete method.
The exact error I get is "Unhandled exception at 0x013214D6 in EXE: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00152FFC)." This occurs in my print function after I delete by coordinates but not if I delete by name.
bool BinaryTree::DeleteByName(string city)
{
if (GetRoot() != NULL)
{
return (DeleteByName(GetRoot(), city));
}
return false;
}
TreeNode* BinaryTree::DeleteByName(TreeNode *node, string city)
{
if (node == NULL)
{
return node;
}
else if (city < node->Data.name)
{
node->Left = DeleteByName(node->Left, city);
}
else if (city > node->Data.name)
{
node->Right = DeleteByName(node->Right, city);
}
else
{
if (node->Left == NULL && node->Right == NULL)
{
delete node;
node = NULL;
}
else if (node->Left == NULL)
{
TreeNode* temp = node;
node = node->Right;
delete temp;
}
else if (node->Right == NULL)
{
TreeNode* temp = node;
node = node->Left;
delete temp;
}
else
{
cout << "Else";
TreeNode* temp = MinPtr(node->Right);
node->Data = temp->Data;
node->Right = DeleteByName(node->Right, temp->Data.name);
}
}
return node;
}
bool BinaryTree::DeleteByCoord(pair<double, double> coords)
{
if (GetRoot() == NULL)
{
return false;
}
else
{
return DeleteByCoord(GetRoot(), coords);
}
}
bool BinaryTree::DeleteByCoord(TreeNode* node, pair<double, double> coords)
{
bool result;
if (node == NULL)
{
return false;
}
else
{
if (node->Data.coordinates.first == coords.first && node->Data.coordinates.second == coords.second)
{
return (DeleteByName(node, node->Data.name));
}
result = DeleteByCoord(node->Left, coords);
if (result == true)
{
return result;
}
return DeleteByCoord(node->Right, coords);
}
}
void BinaryTree::Insert(City city)
{
TreeNode* temp = new TreeNode(city);
if (GetRoot() == NULL)
{
root = temp;
}
else
{
Insert(temp, GetRoot());
}
}
void BinaryTree::Insert(TreeNode* toAdd, TreeNode* addHere)
{
if (toAdd->Data < addHere->Data)
{
if (addHere->Left != NULL)
{
Insert(toAdd, addHere->Left);
}
else
{
addHere->Left = toAdd;
}
}
else if (toAdd->Data > addHere->Data)
{
if (addHere->Right != NULL)
{
Insert(toAdd, addHere->Right);
}
else
{
addHere->Right = toAdd;
}
}
}
void BinaryTree::InOrderTraversal(TreeNode* node)
{
if (node != NULL)
{
InOrderTraversal(node->Left);
cout << node->Data << endl;
InOrderTraversal(node->Right);
}
}
void BinaryTree::InOrderTraversal()
{
InOrderTraversal(GetRoot());
}
TreeNode* BinaryTree::GetRoot()
{
return root;
}
TreeNode* BinaryTree::MinPtr(TreeNode* node)
{
while (node->Left != NULL)
{
node = node->Left;
}
return node;
}
When you delete the node you also need to update parent pointer that points to deleted node. Pay attention here:
when you call DeleteByName directly it searches required node and returns NULL pointer which automatically set to parent node pointer:
else if (city < node->Data.name)
{
node->Left = DeleteByName(node->Left, city);
}
else if (city > node->Data.name)
{
node->Right = DeleteByName(node->Right, city);
}
but when you call DeleteByName from coordinates method you do not reset parent's Left/Right pointers:
if (node->Data.coordinates.first == coords.first && node->Data.coordinates.second == coords.second)
{
return (DeleteByName(node, node->Data.name));
}
in its turn as DeleteByName already receives required node, it does not perform recursive call and does not reset parent's pointers either:
else
{
if (node->Left == NULL && node->Right == NULL)
{
delete node;
node = NULL;
}
//... same here
}
NOTE: There are many more problems in your code. Some that strike the eye:
DeleteByName returns pointer, but DeleteByCoord returns bool, you use pointer as a boolean type in DeleteByCoord
Avoid to compare doubles directly, the comparison result can be wrong. See the question and explanation for the details.
I am having trouble getting my remove300 and removeNode300 function working correctly when I remove the root of the tree. (In my case 8). Everything works right(compiling wise), but when I call me inView function, which displays the numbers in the binary tree in ascending order, it takes that 8 out and just puts the highest number in 8's place.
For example:
I insert these numbers in this order, 8,4,12,2,6,10,14,20 and call me remove function to remove 8. I get this output 2,4,5,20,10,12,14. I want it to be 2,4,6,10,12,14,20.
If I can get some help on this on why this process isn't working please let me know. Also let me know if I have to add anything to this post inorder to help you.
Struct definition:
typedef float Element300;
struct TreeNode300;
typedef TreeNode300 * TreePtr300;
struct TreeNode300
{
Element300 element;
TreePtr300 left;
TreePtr300 right;
};
Remove Function:
void BST300::remove300(const Element300 element, TreePtr300 & root)
{
if(root == NULL)
{
cerr << "Error: Remove Failed!" << endl;
}
else if(element == root->element )
{
removeNode300(root);
}
else if(element < root->element)
{
remove300(element, root->left);
}
else
{
remove300(element, root->right);
}
return;
}
Remove Node function:
void BST300::removeNode300(TreePtr300 & root)
{
TreePtr300 tempPointer = NULL;
if(root->left == NULL && root->right == NULL)
{
delete root;
root = NULL;
}
else if(root->right == NULL)
{
tempPointer = root;
root = root->left;
tempPointer->left = NULL;
delete tempPointer;
}
else if(root->left == NULL)
{
tempPointer = root;
root = root->right;
tempPointer->right = NULL;
delete tempPointer;
}
else
{
findMaxNode300(root->right, tempPointer);
root->element = tempPointer->element;
delete tempPointer;
}
tempPointer = NULL;
return;
}
find Maximum value function:
void BST300::findMaxNode300(TreePtr300 & root, TreePtr300 & tempPointer)
{
if(root->right == NULL)
{
tempPointer = root;
root = root->left;
tempPointer->left = NULL;
}
else
{
findMaxNode300(root->right, tempPointer);
}
return;
}
Just showing how the node of the binary tree looks like. I'm not sure what is wrong but I have a feeling it has something to do with the function being private. How I can compare the private data so I can see if the value I am looking for is inside that node?
class binarytree
{
private:
class node
{
public:
int data;
node * left;
node * right;
node (int x)
{
data = x;
left=NULL;
right=NULL;
}
};
node * root;
This is how I insert the node
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
//insert left
insert(x, r->left);
}
else
{
//insert right
insert(x, r->right);
}
}
}
Here is the part of the code that gives me trouble when I try to compare x to r->data the program crashes and gives me the error message " Access violation reading location 0x00000000"
void remove(int x, node * &r)
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
This is where the functions are publicly. Then I call the private functions so I can manipulate the private tree.
public:
binarytree()
{
root = NULL;
}
~binarytree()
{
//tooo: write this
}
//return true if empty, false if not
bool empty()
{}
void insert(int x)
{
insert(x, root);
}
void remove(int x)
{
remove(x,root);
}
};
EDIT: Here is another function of the program that works but might be causing r to point to NULL.
int extractMin(node * &r)
{
if(r->left == NULL)
{
if(r->right == NULL)
{
return r->data;
}
else
{
int x = r->data;
r = r->right;
return x;
}
}
else
{
return extractMin(r->left);
}
}
Here is the new function to check to see if r is NULL
void remove(int x, node * &r)
{
if(r == NULL)
{
cout<<"why am I null?"<<endl;
}
else
{
if(x == r->data)
{
if(r->right == NULL && r->left == NULL)
{
r = NULL;
}
else if(r->right == NULL && r->left != NULL)
{
r = r->left;
}
else if(r->right != NULL && r->left == NULL)
{
r = r->right;
}
else
{
node * temp;
temp =r;
r = r->left;
while(r->right != NULL)
{
r = r->right;
}
r->right = temp->right;
delete temp;
}
}
else if ( x < r->data)
{
remove(x, r->left);
}
else if (x > r->data)
{
remove(x , r->left);
}
}
}
you should always check for NULL before trying to get to the inner members:
void remove(int x, node * &r)
{
if(r != NULL)
{
// Your code
}
}
you call to remove with r as NULL and then try to check r.Left. then here you have access violation
also i must ask, did any if this worked for you? specifically insert wont work this way.
try
void insert(int x, node * &r)
{
if(r==NULL)
{
r= new node(x);
}
else
{
if(x < r->data)
{
if(r->left != NULL)
{
//insert left
insert(x, r->left);
}
else
{
r->left = new node(x);
}
}
else
{
if(r->right != NULL)
{
//insert right
insert(x, r->right);
}
else
{
r->left = new node(x);
}
}
}
}
r is null somehow. You need to check if the r passed in is NULL, or check if the root is non-null, and call remove on children only if they exist.
Well it the error says, r is pointing to NULL when you try to derefference it.
So you have to make sure when you assign memmory to r it doesn't return NULL.
binarytree()
{
root = NULL;
}
void remove(int x)
{
remove(x,root);
}
In your case you are trying to derefference NULL (as the error says) This happens in your code when you are calling a remove before you have called an insert.
You simply should check at the beginning of remove for r isn't pointing to NULL.
Or even better, make sure you won't parse in r when its NULL.
You are comparing x to the root. When your tree is empty, root == nullptr. You should check to see if r == nullptr first, as in:
bool remove(int x, node * &r) {
if(!r) {
return false; // Indicate whether removal succeeded
}
//... etc.
}