Consider this code (quoted from geeksforgeeks.org, author Tushar Roy) which calculates true or false if the path from a root to a leaf has keys that sum to a specified value:
bool hasPathSum(struct node* node, int sum)
{
/* return true if we run out of tree and sum==0 */
if (node == NULL)
{
return (sum == 0);
}
else
{
bool ans = 0;
/* otherwise check both subtrees */
int subSum = sum - node->data;
/* If we reach a leaf node and sum becomes 0 then return true*/
if ( subSum == 0 && node->left == NULL && node->right == NULL )
return 1;
if(node->left)
ans = ans || hasPathSum(node->left, subSum);
if(node->right)
ans = ans || hasPathSum(node->right, subSum);
return ans;
}
}
In this code, the author has used the logical OR operator in his assignments to a variable ans
which he returns to avoid overwriting a return of true with a return of false. I have refactored the code into:
int hasPathSum(Treelink tree, int sum){
if ( !tree ) { //succesful path found
return (sum == 0);
} else {
sum -= tree->item;
if ( (sum == 0) && (!tree->left && !tree->right))
return 1;
return hasPathSum(tree->left, sum) || hasPathSum(tree->right, sum);
}
}
Although it is obvious with this case that using a temporary variable and/or the logical OR operator are effective in preventing overwrites of recursive returns, what are some best methods for carrying a value up a recursive call?
EDIT
Conversely, let us consider a slightly contrived example; Given an improperly ordered binary tree (say, key 100 as root with left child's key as 5 and right child's key as 2), find the minimum key from the tree recursively. I would naively approach this as so:
Disclaimer: written but not compiled.
int findMin(Tree tree, int min) {
if (!tree) return 0; //defensive check
if ( tree->item < min && (tree->left || tree->right) ) {
//Can go deeper and reestablish the min in both directions
if ( tree->left )
min = findMin(tree->left, tree->item);
if ( tree->right )
min = findMin(tree->right, tree->item);
} else if ( tree->item >= min && (tree->left || tree->right ) ) {
//can go deeper but should not reestablish the min
if ( tree->left )
min = findMin(tree->left, min);
if ( tree->right )
min = findMin(tree->right, min);
} else {
return min; //return min's final value
}
}
It would presumably be called via findMin(testTree, testTree->item)
. Fundamentally; we are forced to go down both branches from the root to explore and find a key that might be anywhere in the tree (even the root itself!) We know we have to make assignments to 'pull up' the right key, however this would most probably overwrite the 'true' min of the previous call (the way this is currently written) unless we did some kind of bounded check on each assignment e.g.
tmpmin = findMin(tree->left);
min = (min < tmpmin) ? min : tmpmin;
We could also perhaps have two separate variables (as this is a binary tree, after all) that specify the left min and the right min and merely return the min of the two. In these cases I am still using some kind of temporary variables to piggy back to its original caller. Ultimately, I am curious about generic heuristics regarding avoiding these types of mistakes when designing recursive algorithms.