BST search key in C++ - c++

I was trying to implement BST search method for finding a key in BST. Below is the code.
node* search_key(node **root,int key)
{
if (*root == NULL || (*root)->data == key ){
return (*root);
}
if ( key < (*root)->data ) {
search_key(&(*root)->left, key);
}
else{
search_key(&(*root)->right, key);
}
}
Above code was always returning null except for searching root node. I modified the code to the following and it is working perfectly.
Can anyone please explain the recursion involved here?
node* search_key(node **root,int key)
{
if (*root == NULL || (*root)->data == key ){
return (*root);
}
if ( key < (*root)->data ) {
return search_key(&(*root)->left, key); // note return
}
else{
return search_key(&(*root)->right, key);
}
}

In the first code snippet you have a function which is supposed to return something, but doesn't do that in some cases. That will lead to undefined behavior.
In the second snippet you actually return something in all paths of the function.

When you call same function or another function with a function it make a call of that function and when it completed call comes back to the caller function here call is coming back to caller but no result as you are not returning any result.
So after returning value to the called function it starts showing correct result.
Follow this image of factorial function for better understanding

In the binary tree there are 2 roots the left and right root. So your first condition says if you are in the last node (where root == NULL) or you find the key (value on root->data match the value of key) so, the program returns the exact block that contain the data (there it is not recursive).
if (*root == NULL || (*root)->data == key ){
return (*root);
The second condition say if the key is less than the value stored into root->data, the node go to the left root. So, the line returnsearch_key(root->left,key)` means: redo the same operation but now go to the left root.
if ( key < (*root)->data ) {
return search_key(&(*root)->left, key);
}
So, let's imagine that in the left root, the root->data is higher than the key,
so the line return search_key(root->right,key) means redo this operation but now go to the right root.
else{
return search_key(&(*root)->right, key);
}
The recursion will end only if you find the key somewhere or you check everything and you did not find anything. So remember, recursion means redo it again and again.

While implementing recursion we should always make sure that for each condition when we call the function recursively, then there should be a "return" statement so that immediate caller of a function will get the resultant value and therefore at the end of the recursion final value will be returned.
What in case if return statement is not used:
If there is no return statement, then the value computed by the current function will be discarded or unsaved so that the immediate caller won't get any value and further it will end up with undefined behaviour.

Related

recursive function calling in c++

Whats the difference between
return(checkBst(root->left, minvalue, root) && checkBst(root->right, root, maxvalue));
and
return(checkBst(root->left, minvalue, root));
return(checkBst(root->right, root, maxvalue));
My whole programme looks like this
bool checkBst(node *root, node * minvalue, node * maxvalue){
if(root == NULL){
return true;
}
if((minvalue && root->data <= minvalue->data) || (maxvalue && root->data >= maxvalue->data)){
return false;
}
return(checkBst(root->left, minvalue, root) && checkBst(root->right, root, maxvalue));
// return(checkBst(root->left, minvalue, root));
// return(checkBst(root->right, root, maxvalue));
}
To be frank, you cannot have a return for each of the function calls. This is because return is the last statement executed in a function before the control is given back to the calling function.
In your case, the second function is NEVER called. So, if your first function returns true, it never calls the 2nd function. Had the 2nd function result been false, the answer you get will be erroneous.
You still need to have a return statement at the end of both statements and capture the value returned by the functions.
I mean this statement:
return(checkBst(root->left, minvalue, root) && checkBst(root->right, root, maxvalue));
is equal to:
ret1 = checkBst(root->left, minvalue, root);
if(ret1)
return checkBst(root->right, root, maxvalue);
else
return false;
Recursion is not about putting everything in one line. That is just a coding style. The Comment by Pepijn Kramer and Some programmer dude talk about the optimization that you can get with writing in the same line. If the 1st half is false, you don't need to evaluate the 2nd half and that saves computation time and energy.
Recursion is about doing repetitive tasks by calling the same function within itself and using the result of it to give the final result.
In your case, Initially you send the whole tree. Then you divide the problem into 2 halves by calling the function for each of the sub-trees.
In each function call you take care of the terminal conditions. That is the first and second lines that you have. Those are the only cases where you don't call more functions. You are getting a return value.
Now, this return value should be propagated back to the calling function

function that returns the number of nodes in a certain level of a binary search tree

I have to create a function getNodesatLevel that returns the number of nodes at a level, however, I'm getting a "may reach end of void function" error. This is for a Binary Search tree, and I'm required to use recursion for this function.
int TreeType::getNodesAtLevel(TreeNode * &node, int level, ItemType * mainArr)
{
int currentLevel = 0;
int NodeCount = 1;
if(currentLevel == level)
{
NodeCount++;
return NodeCount;
}
else if(currentLevel != level)
{
currentLevel++;
if(node->left != NULL)
getNodesAtLevel(node->left, level, mainArr);
if(node->right != NULL)
getNodesAtLevel(node->right, level, mainArr);
}
}
The error is basically what it says on the tin: your function can reach the end without returning a value.
To see why, let's just look at your outer if statement:
if(node->left != NULL)
//...
if(node->right != NULL)
//...
//...
What happens if both node->left and node->right are null? You don't handle this case at all. That's a bug.
Secondly (and arguably most importantly) you call yourself recursively, but don't do anything with the return value of your function. You don't return it, and you don't save it for later either. That means nothing really happens to it. It just gets lost.
Because of this, your function won't return this value at all. That creates situations in which nothing is returned.
So, to fix this, figure out what you want to do with the recursive return value of your function and either a) save it in a temporary variable, or b) simply return it. Which one you choose will depend on what you want your function to count.
Also, make sure you return a value even if both sides of the tree are NULL.

If/Else statement returns

This section of code keeps throwing an error, "not all control paths return a value". I'm not entirely sure how to rewrite this so that I can fix the error. Other than the returns, this is what I need this section of code to do. Should I create a new variable that I declare within the if/else statement and then have the return for that variable right before the ending bracket?
node * LList::search(int srchKey)
{
node * p = head;
while (p != NULL)
{
if (p->key == srchKey)
{
return p;
}
else
{
return NULL;
}
p = p->next;
}
}
If head is NULL, search() will exit without reaching any return statement. The return value will be indeterminate. That is what the compiler is complaining about.
If head is not NULL, search() will check only the first node and then return a value, it will not search the whole list. Because of that, the return NULL; statement should not be inside the loop at all. It will exit search() as soon as it encounters an element that doesn't match, rather than continuing to the next element in the list.
This is similar to the problem I describe in Searching array reports "not found" even though it's found.
You should wait until the loop ends before doing return NULL;. If you get there, it means the item being searched for really wasn't found.
node * LList::search(int srchKey)
{
node * p = head;
while (p != NULL)
{
if (p->key == srchKey)
{
return p;
}
p = p->next;
}
return NULL;
}
You need another return statement after the while loop. One possible code path is that the program never enters the while loop. A simple
return NULL;
should fix it.
EDIT: Also, your loop will only ever make one pass through. I would remove the (if p == NULL) block; it is useless. I see your intent, but the way to implement it is how I described above.
when while condition is false, then you do not have return.
Add a return outside while in case you do not enter the loop.
Moreover, p = p->next; will never be executed because you exit the loop before reaching it because of if-else.
Regarding the logic, It seems to me that you do not need the else part at all. try to omit it and place return NULL before the end of the routine.

printing the contents of a Binary Search Tree recursively?

void MovieTree::printMovieInventory(MovieNode* node)
{
if(node)
{
while(node->rightChild!=NULL or node->leftChild!=NULL)
{
std::cout<<"Movie:"<<node->title<<" "<<node->quantity<<std::endl;
if(node->rightChild)
{
printMovieInventory(node->rightChild);
}
if(node->leftChild)
{
printMovieInventory(node->leftChild);
}
}
}
else
{
std::cout<<"No movies in list!"<<std::endl;
}
}
I'm not sure if this function is causing my issue or if it's my adding function but I feel as though the logic to this is correct. Am I missing something?
Edit::
My issue is that it's resulting in an infinite loop and it's not properly printing all associated children of the tree
Use of while in the function is wrong. It needs to be if. Otherwise, the function never breaks out of the while loop.
FWIW, that function can be simplified to:
void MovieTree::printMovieInventory(MovieNode* node)
{
if(node)
{
std::cout<<"Movie:"<<node->title<<" "<<node->quantity<<std::endl;
printMovieInventory(node->rightChild);
printMovieInventory(node->leftChild);
}
}
In addition to the problem with the while loop, this can also never print leaf nodes, as you don't print the node itself if it doesn't have either a left or a right child.
while(node->rightChild!=NULL or node->leftChild!=NULL)
{
std::cout<<"Movie:"<<node->title<<" "<<node->quantity<<std::endl;
it should be
if(node)
print node
if left
recurse left
if right
recurse right
Couple of Things here.
From the code as i understand, you are trying to print in a pre-order fashion.
the While Loop is unnecessary and that is what is causing the infinite loop
Lets say you have two nodes root and root->left
your function will print root, call the function recursively on root' = root->right (will not print anything this time because root'->left is NULL and root'->right is NULL). Then the function print(root') returns to its caller which is print(root). This time it will not exit out of the while Loop because the while condition is always true, ergo the infinite Loop.
you can simply do this
Print(root)
cout << root;
if(root->right != NULL)
Print(root->right);
if(root->left != NULL)
Print(root->left);
TO display "No Movies" just check if root == NULL before calling this recursive function Print(root);

How to add children to BST

I'm trying to make/create a BST, but it doesn't seem to work properly. I've literally been sitting here for hours trying to figure out what's going on. It's gotten to the point where I've drawn a million diagrams to figure this out, yet my code fails me. I need to pass in a root node into a function. Then I need to traverse through the tree until I find that the parent string parameter of the function coincides with the tree parent node's string. If I do find it, I must insert the string into the parent, and create two new children from that parent. If I can't find the parent string, then I return false.
bool insertNode(BSTNode *n, char* parentQ, char* leftQ, char* rightQ)
{
if(n->Q == parentQ)
{
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q != parent)
{
insertNode(n->left,parentQ,leftQ,rightQ);
insertNode(n->right,parentQ,leftQ,rightQ);
}
else
return false;
}
Also I need to make another method that takes the tree that I have established, and corrects the strings. So the method modifies the parent string, if found, and looks at its children, if found, and replaces those strings with those found in the method parameters. It's sort of like adding a subtree without screwing the entire tree up. Thanks in advance!
bool changeNode(BSTNode *n,char* parentQ, char* leftQ, char* rightQ)
{
if(n->Q == leftQ)
{
n->Q = parentQ;
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q == rightQ)
{
n->Q = parentQ;
n->left = new BSTNode(leftQ);
n->right = new BSTNode(rightQ);
return true;
}
else if(n->Q != leftQ)
{
changeNode(n->left,parentQ,leftQ, rightQ);
}
else if(n->Q != rightQ)
{
changeNode(n->right,parentQ,leftQ,rightQ);
}
return false;
}
You didn't even mention what the error was, example input / expected output, but shouldn't you be checking whether the current node actually has a left and right child, before calling the function with those children?
else if(n->Q != parentQ) // <--- you have a typo in this line, "parent"
{ // (and you don't even need the 'if')
insertNode(n->left,parentQ,leftQ,rightQ);
insertNode(n->right,parentQ,leftQ,rightQ);
// in this case you return nothing! corrupted return value
}
^ this seems very error-prone, especially null-pointer. You should turn it into something like:
else
{
if(n->left != NULL) // take a look at nullptr if you have C++11
if(insertNode(n->left,parentQ,leftQ,rightQ)) return true;
if(n->right != NULL)
if(insertNode(n->right,parentQ,leftQ,rightQ)) return true;
return false;
}
Otherwise your true return never gets propagated back beyond the first return, so then you're always returning false unless in the only case where the root of the tree is actually the node you were searching for.
Also, do not compare two char arrays using ==, unless n->Q is actually an std::string. You should use if(strcmp(n->Q, parentQ) == 0) otherwise.
Your second piece of code, however, is just a mess. You need to take a better look at what exactly will be happening on your else if's and see if it is actually doing what you want (hint: it isn't), as you currently only execute at most 1 of the code blocks, even if more than one condition is true.