I've got this call
productTree.displayNode(productTree.newsearchTree(search, productTree.Root()));
Calling these functions
void Tree::displayNode(Node* node) {
if (node != NULL) {
cout << node->productdata << endl;
}
}
Node* Tree::newsearchTree(string search, Node* node) {
if (node != NULL) {
newsearchTree(search, node->left);
if (search == node->productdata.getName()) {
return node;
}
newsearchTree(search, node->right);
}
}
Node* Root() { return root; };
Which produces a garbage output when trying to display the returned node.
And yet, I can traverse my tree and display it easily this way:
This call:
productTree.Inorder(productTree.Root());
Functions:
void Tree::Inorder(Node* node) {
if (node != NULL) {
Inorder(node->left);
displayNode(node);
Inorder(node->right);
}
}
And where I am confused is how are they different?
Edit: Thank you for your help, I modified the code as below and it works fine now:
Node* Tree::newsearchTree(string search, Node* node) {
if (node != NULL) {
newsearchTree(search, node->left);
if (search == node->productdata.getName()) {
return node;
}
newsearchTree(search, node->right);
}
return NULL;
}
void Tree::displayNode(Node* node) {
if (node != NULL) {
cout << node->productdata << endl;
}
else if (node == NULL) {
cout << "Product not found" << endl;
}
}
Yep, that's still broken. This finally fixed it I believe:
Node* Tree::newsearchTree(string search, Node* node) {
if (node != NULL) {
if (search == node->key) {
return node;
}
if (search < node->key) {
return newsearchTree(search, node->left);
}
else {
return newsearchTree(search, node->right);
}
}
else return NULL;
}
Let me add comments inline to make it clear what your Tree::newsearchTree does.
Node* Tree::newsearchTree(string search, Node* node) {
if (node != NULL) {
newsearchTree(search, node->left); // burn CPU but leaves no side effect
if (search == node->productdata.getName()) {
return node; // return node only if the root node equals 'search'
}
newsearchTree(search, node->right); // burn CPU without side effect
}
// In majority of the cases (root node != 'search'): return nothing.
}
Because typically newsearchTree() returns nothing, when you call productTree.displayNode(productTree.newsearchTree(...)) you basically print garbage.
Related
I want to try make insertion of complete binary tree using recursion . I make a piece of code and I cannot catch problem why value not inserted. I make height function and count nodes function with help of these function and recursive call I want to insert new node in Complete binary tree. In main get root by using get root function then send to insert function
#include<iostream>
#include<math.h>
using namespace std;
struct node{
int data;
node *left,*right;
};
class cbt{
node *root;
public:
cbt()
{
root=NULL;
}
node* get_node()
{
return root;
}
node* newNode(int key)
{
node* temp1 = new node;
temp1->data = key;
temp1->left = temp1->right = NULL;
return temp1;
}
void CBT_inseration(node* temp,int data)
{
node *ptr;
ptr=newNode(data);
if(root==NULL)
{
root=ptr;
return;
}
else
{
height = f_height(temp->left);
int excepted_node = pow(2,height)-1;
int left_tree_node_count = countNumNodes(temp->left);
int right_tree_node_count = countNumNodes(temp->right);
if(left_tree_node_count==right_tree_node_count)
{
CBT_inseration(temp->left,data);
}
else if(excepted_node != left_tree_node_count)
{
if(temp->left == NULL)
{
temp->left = ptr;
return;
}else
{
CBT_inseration(temp->left,data);
}
}
else if(temp->right == NULL)
{
temp->right=ptr;
return;
}
else if(excepted_node != left_tree_node_count)
{
if(temp->left == NULL)
{
temp->left=ptr;
return;
}
else
{
CBT_inseration(temp->right,data);
}
}
}
}
void print(node *root) {
if (root == NULL)
return;
print(root->left);
cout << root->data << " ";
print(root->right);
}
};
int main()
{
cbt obj;
node *r=NULL;
obj.CBT_inseration(obj.get_node(),4);
obj.CBT_inseration(obj.get_node(),3);
obj.CBT_inseration(obj.get_node(),5);
obj.CBT_inseration(obj.get_node(),8);
obj.print(obj.get_node());
return 0;
}
You would need to go through a debugger to see what is wrong with your code. I will tell you how I would do this:
First, you need a function to check if the tree is full. We will reuse your functions to do this:
bool isTreeFull(node* head) {
return head != NULL && countNumNodes(head) == (1 << find_height(head)) - 1;
}
Then for inserting I have to check if the number of nodes on each side are the same. This tells me that I am allowed to move one level deeper on the left side. If the number of nodes aren't the same, then I only move on to insert on the right subtree if the left subtree is full:
void CBT_inseration(int data) {
root = insert(root, data);
}
node* insert(node* head, int data) {
if (head == NULL) {
head = newNode(data);
} else {
int leftCount = countNumNodes(head->left);
int rightCount = countNumNodes(head->right);
if (leftCount == rightCount) {
head->left = insert(head->left, data);
} else {
if (isTreeFull(head->left)) {
head->right = insert(head->right, data);
} else {
head->left = insert(head->left, data);
}
}
}
return head;
}
Then you would call it like:
cbt obj;
obj.CBT_inseration(4);
obj.CBT_inseration(3);
obj.CBT_inseration(5);
obj.CBT_inseration(6);
obj.CBT_inseration(8);
obj.print(obj.get_node()); // 6 3 8 4 5
I have implemented a function "searchkey" in order to return a node in a binary search tree if the key is present but it is returning the root node. I have added a minimal reproducible code.
While the same iterative method works. Also which would be the better way to implement this recursive or iterative.
template<class T>
class Node{
public:
T m_data;
Node<T>* m_left;
Node<T>* m_right;
Node(T data){
m_data=data;
m_left=nullptr;
m_right=nullptr;
}
};
template<class T>
class bst {
private:
Node<T>* root;
public:
bst() { root = nullptr; }
~bst() { deltree(root); }
void addnode(Node<T>* node, T data) {
if(this->root == nullptr) {
Node<T>* new_node= new Node<T>(data);
this->root = new_node;
} else if(data > node->m_data) {
if(node->m_right != nullptr) {
addnode(node->m_right, data);
} else {
Node<T>* new_node = new Node<T>(data);
node->m_right = new_node;
}
} else if(data < node->m_data) {
if(node->m_left != nullptr) {
addnode(node->m_left, data);
} else {
Node<T>* new_node = new Node<T>(data);
node->m_left = new_node;
}
}
}
void addnode(T data) { addnode(this->root, data); }
Node<T>* searchkey(T data) {
return searchkey(data,this->root);
}
Node<T>* searchkey(T data, Node<T> *node) {
if (node == nullptr) { // <-- check if node is null
return node;
} else if (data == node->m_data) {
return node;
} else if (node->m_data > data) {
searchkey(data, node->m_left);
} else if (node->m_data < data) {
searchkey(data, node->m_right);
}
return node;
}
void deltree(Node<T>* node) {
if(node) {
deltree(node->m_left);
deltree(node->m_right);
delete node;
}
};
It seems you are missing a few return statements in your search function. Also, the test for data == node->m_data isn't needed. The fallback return at the end of the function means that a match is found if you return when doing the recursive calls.
Node<T>* searchkey(T data, Node<T> *node) {
if (node == nullptr) { // <-- check if node is null
return node;
} else if (node->m_data > data) {
return searchkey(data, node->m_left);
} else if (node->m_data < data) {
return searchkey(data, node->m_right);
}
return node; // match found
}
In your original code, you called searchkey but did not return the value it returned. The function instead continued to return the same node that was given as an argument to the function, yielding the wrong result in all cases except when searching for the value stored in the root node.
An alternative view:
Node<T>* searchkey(T data, Node<T> *node) {
if (node != nullptr) {
if (node->m_data > data) {
node = searchkey(data, node->m_left);
} else if (node->m_data < data) {
node = searchkey(data, node->m_right);
} // else { here we know that node->m_data == data }
}
return node; // nullptr or the matching Node* is returned
}
Also which would be the better way to implement this recursive or iterative.
There's no definite answer. If you are likely to store many values, so the search depth becomes large, you don't want recursive calls because you may then get a stack overflow.
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;
}
After a few questions and some nice answers and friendly helpers here. I got the sulotion to my porblem with the deleting in the binary tree, i got suggested that, i can not just delet the largest number in the tree cause its may not the last or it has childrens 1 ,2 or none, so i made the code down below, i used a lot commenting hope that can help you people help me. What i actually dont know now, is how do i call this RemoveLargest() function in my public and then later in main, even though i dont know if the code will run properly.
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot) //Insert elements into the tree start.
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);
} //end.
void PrintTree(Node* theRoot) //print me the tree /start
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" \n";
PrintTree(theRoot->rChildptr);
}
} //end.
T Largest( Node* theRoot) // show me largest number /start.
{
if ( root == NULL )
{
cout<<"There is no tree";
return -1;
}
if (theRoot->rChildptr != NULL)
{
return Largest(theRoot->rChildptr);
}
T value = theRoot->data;
return value;
} //end.
void RemoveLargest(Node* theRoot) //remove the largest priority number from tree /start.
{
Node* current; //the current tree?
Node* parent; //the parent of the current node?
current=theRoot;
// 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((current->lChildptr == NULL && current->rChildptr != NULL)||(current->lChildptr != NULL && current->rChildptr == NULL))
{
if(current->lChildptr == NULL && current->rChildptr != NULL)
{
if(parent->lChildptr==current)
{
parent->lChildptr = current->rChildptr;
delete current;
}
else
{
parent->rChildptr = current->rChildptr;
delete current;
}
}
else //left child ok, no right child
{
if(parent->lChildptr==current)
{
parent->lChildptr = current->lChildptr;
delete current;
}
else
{
parent->rChildptr = current->lChildptr;
delete current;
}
}
return;
}
//We found a leaf(a node with not a single child)
if(current->lChildptr == NULL && current->rChildptr == NULL)
{
if (parent->lChildptr == current)
parent->lChildptr = NULL;
else
parent->rChildptr = NULL;
delete current;
return;
}
//Node with 2 children
// replace node with smallest value in right subtree
if (current->lChildptr != NULL && current->rChildptr != NULL)
{
Node* checkr;
checkr = current->rChildptr;
if((checkr->lChildptr == NULL)&&(checkr->rChildptr == NULL))
{
current=checkr;
delete checkr;
current->rChildptr = 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 ((current->rChildptr)->lChildptr != NULL)
{
Node* lcurr;
Node* lcurrp;
lcurrp = current->rChildptr;
lcurr = (current->rChildptr)->lChildptr;
while(lcurr->lChildptr != NULL)
{
lcurrp = lcurr;
lcurr = lcurr->lChildptr;
}
current->data = lcurr->data;
delete lcurr;
lcurrp->lChildptr = NULL;
}
else
{
Node* temp;
temp = current->rChildptr;
current->data = temp ->data;
current->rChildptr = temp->rChildptr;
delete temp;
}
}
return;
}
};
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
T Largest()
{
return Largest(root);
}
void RemoveLargest()
{
RemoveLargest();
}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(5);
myBT->AddItem(1);
myBT->AddItem(4);
myBT->AddItem(2);
myBT->AddItem(3);
//for(int i = 0; i < 10; i++) //randommal tolti fel/fill with random
//myBT->AddItem(rand() % 100);
cout << "BinaryTree:" << endl; //kilistazaa a fat/ list my tree
myBT->PrintTree();
cout << "Largest element: " << myBT->Largest() << endl; //visszaadja a legnagyobb elemet/shows the largest number
myBT->RemoveLargest(); //suposed to delet the largest number
myBT->PrintTree(); //shows list again
}
edited the code, now its running, its creating the tree, shows the largest, but after i call my remove function still crashing... =/
Like I said before, I think you're making things overly complicated. You have to think of what it means that your node is the largest one, in the context of a binary search tree and the relationship between the keys in its nodes.
If a node is the largest one in the tree it cannot possibly have a right child pointer, because the right child would have to have a larger key. And then, if you know that it has at most a left child, you just replace your node with its possibly null left child, and you're done.
T ExtractLargest(Node*& n){
if (!n)
return -1;
if (n->rChildptr)
return ExtractLargest(n->rChildptr);
T result = n->data;
Node *d = n;
n = n->lChildptr;
delete d;
return result;
}