Count nodes with specific number of children in a binary tree? - c++

I have this challenging exercise I got from a book about c++, and i'm not sure how to tackle this problem.
I must define a function called treeNodeCount() which returns the number of nodes in a binary tree (easy enough), and I also have to define an overloaded function that takes an int(0,1, or 2) which represents the number of children, and the function should return the nodes that have that specific number of children.
treeNodeCount should both use a function called nodeCount(elemType root) to do the recursion necessary to count the nodes(so basically all the work).
challenge number one says that I can add a second parameter to nodeCount which takes the number of children for the nodes that we want to count.
Challenge number two says that we cannot use a second parameter (this is the tough part)
I was able to do challenge one and here is what I came up with:
template <class elemType>
int binaryTreeType<elemType>::nodeCount(nodeType<elemType> *p, int a ) const
{
if (p == NULL){
return 0;
}
else if (a == 0 && p->lLink == NULL && p->rLink == NULL){
return 1 + nodeCount(p->lLink, a) + nodeCount(p->rLink, a);
}
else if (a == 1 && (p->lLink != NULL ^ p->rLink != NULL)){
return 1 + nodeCount(p->lLink, a) + nodeCount(p->rLink, a);
}
else if (a == 2 && p->lLink != NULL && p->rLink != NULL){
return 1 + nodeCount(p->lLink, a) + nodeCount(p->rLink, a);
}
else if (a == -1){
return nodeCount(p->lLink, a) + nodeCount(p->rLink, a) + 1;
}
return nodeCount(p->lLink, a) + nodeCount(p->rLink, a);
}
template <class elemType>
int binaryTreeType<elemType>::treeNodeCount(int a) const{
return nodeCount(root, a);
}
This seems to work fine but i am convinced that there has to be a better way.
I was not able to do challenge 2 though, and i have no idea what to do (is it even possible)

You can scrunch down your logic and make it a bit more straightforward by implementing a function to return the number of children given a node.
template <class elemType>
int nodeSize(nodeType<elemType>* node) const
{
int count = 0;
if (node->lLink)
++count;
if (node->rLink)
++count;
return count;
}
template <class elemType>
int binaryTreeType<elemType>::nodeCount(nodeType<elemType>* node, int count) const
{
if (node)
{
if (nodeSize(node) == count || count == -1)
return nodeCount(node->lLink, count) + nodeCount(node->rLink, count) + 1;
return nodeCount(node->lLink, count) + nodeCount(node->rLink, count);
}
return 0;
}
For the second challenge, you need a stack to avoid recursion.
template <class elemType>
int binaryTreeType<elemType>::treeNodeCount(int count) const
{
stack<nodeType<elemType>*> node_stack;
node_stack.push(root);
int num_matches = 0;
while (!stack.empty())
{
nodeType<elemType>* node = node_stack.top();
node_stack.pop();
if (node)
{
if (nodeSize(node) == count || count == -1)
++num_matches;
node_stack.push(node->lLink);
node_stack.push(node->rLink);
}
}
return num_matches;
}
Edit: fixed a goof in the above recursive version. Thanks to David Rodriguez for pointing it out.

Related

c++ how to get depth of a binary tree recursively

I wrote a code that suposed to return the depth of a binary tree from the root to the node who called the function. using recursive way but I faced a problem about how to count the number of times that the function gets called so I whould know how much convexity I passed. Someone know how can I do that?
int BSNode::getDepth(const BSNode& root) const
{
if (this != nullptr)
{
if (root.getData() > this->_data)
{
this->getDepth(*root.getRight());
}
else if (root.getData() < this->_data)
{
this->getDepth(*root.getLeft());
}
else if (root.getData() == this->_data)
{
// return the number that the function counted
}
}
else
{
return 0;
}
}
You should at least return something in every case. And when you arrive at the intended node (having the data you are looking for), then return 0. In all other cases, return what you get from recursion plus 1. If the value is not found then indeed -1 should be returned. And if this -1 is coming back from recursion, it should be returned like that also to the caller (without adding 1).
Here is the code adapted:
int BSNode::getDepth(const BSNode& root) const
{
int temp;
if (this != nullptr)
{
if (root.getData() > this->_data)
{
temp = this->getDepth(*root.getRight());
return temp == -1 ? -1 : temp + 1;
}
else if (root.getData() < this->_data)
{
temp = this->getDepth(*root.getLeft());
return temp == -1 ? -1 : temp + 1;
}
else if (root.getData() == this->_data)
{
return 0;
}
}
else
{
return -1;
}
}

Function to find number of nodes below a certain depth of a BST

I'm trying to make a function that will count the number of nodes greater than a certain depth "k".
Here is my code of the function for traversing the tree and a helper function for finding the depth of each node:
int findDepth(BinaryNode * t, int value, int depth){
if( t == nullptr ){
return 0;
}
if( t->element == value){
return depth;
}
int lowerDepth = findDepth(t->left, value, depth+1);
if(lowerDepth != 0){
return lowerDepth;
}
lowerDepth = findDepth(t->right, value, depth+1);
return lowerDepth;
}
int countDeep( BinaryNode * t, int k ){
int count = 0;
if (t != nullptr){
countDeep( t->left, k );
if (findDepth(t, t->element, 0)){
count++;
}
countDeep( t->right, k );
}
return count;
}
Right now the function always returns 0 and I'm not quite sure why.
consider this:
int countDeep( BinaryNode * t, int k ){
int count = 0;
if (t != nullptr){
countDeep( t->left, k );
if (findDepth(t, t->element, 0)){
count++;
}
countDeep( t->right, k );
}
return count;
}
I didn't carefully read other code snippets, yet this function returns either 0 or 1. Because you discarded the return value of it in recursion. This function can be seen as pure function (although you modyfy the count through ++), so calling it without using its return value is wrong.
So if another function call this one, the count of the function only have one chance to self-increase, I didn't inspect into your code, maybe that "only chance" doesn't exist as well.

Binary Tree numLeaf algorithm not working

I'm writing a program to try and get the number of leaves in a binary tree. What I did was I checked if the current ptr was a leaf, and if not, to keeps going to the next subtree. However, when I run it, it keeps returning 2. What am I doing wrong?
I didn't include the source code because its relatively standard (has a rLink, lLink, etc.). There are no errors when I run this:
template <class elemType>
long int bSearchTreeType<elemType>::getLeaves(nodeType<elemType> * current, long int count) const {
if(current->rLink == NULL && current->lLink == NULL) {
count += 1;
return count;
}
if(current->rLink!=NULL) {
getLeaves(current->rLink);
}
if(current->lLink!=NULL) {
getLeaves(current->lLink);
}
}
template <class elemType>
long int bSearchTreeType<elemType>::leaves() const {
if(this->root!=NULL) {
return this->getLeaves(this->root);
}
}
Edit: I declared the function with count = 1 in the parameter list. Thats why I'm able to to that.
I find a few issues.
1) You are calling return this->getLeaves(this->root); but there is no method with that method signature in the code sample you have here.
bSearchTreeType<elemType>::getLeaves(nodeType<elemType> * current, long int count)
2) Your code doesn't handle cases where the current can be null i.e) for tree's like
2
/
1
3) You are not returning anything after traversing the left and the right sub tree.
You could write something like this
template <class elemType>
long int bSearchTreeType<elemType>::getLeaves(nodeType<elemType> * current)
{
if(current == NULL)
return 0;
if(current->rLink == NULL && current->lLink == NULL)
return 1;
int leftSubTree = getLeaves(current->lLink);
int rightSubTree = getLeaves(current->rLink);
return leftSubTree + rightSubTree;
}

storing the number of certain leaves in the nodes of the binary search tree(optimization)

I have to count for each subtree the number of leaves with even label whose father has odd label and the number of leaves with odd label whose father has even label and store that number in the subtree's node.
For example : this tree (the output is on the left).
This is my code
struct node {
int label;
node*right;
node*left;
int L; //i use this to store the number of leaves
};
void addnodeBST(node*&tree, int l) { //adds a node
if (!tree) {
tree = new node;
tree->label = l;
tree->right = tree->left = 0;
tree->L = 0;
return;
}
if (l < tree->label)
addnodeBST(tree->left, l);
if (l > tree->label)
addnodeBST(tree->right, l);
}
int counter(node*tree, int x) {
if (!tree)
return 0;
if ((!tree->left && !tree->right) && ((x % 2 == 0 && tree->label % 2 ==
1) || (x % 2 == 1 && tree->label % 2 == 0)))
return 1;
return counter(tree->left, tree->label) + counter(tree->right, tree-
>label);
}
void updateNode(node*tree) {
if (!tree)
return;
tree->L = counter(tree, 0);
if (!tree->right && !tree->left)
tree->L = 0;
updateNode(tree->left);
updateNode(tree->right);
}
It works, what is not fine are the functions "counter" and "updateNode" together.
"Counter" counts the number of leaves that are to be counted.
"UpdateNode" utilizes "counter" to count and then store the number of leaves in each subtree into L (which i defined in the struct).
This way i have a recursive function into another recursive function and i visit each node multiple times.
How can i optimize my code?
This way i have a recursive function into another recursive function and i visit each node multiple times.
The part before andmakes your code ugly, but the real devil lies in how you chose to traverse the tree.
In your updateNode function, the value of L for a node is simply sum of it's left and right subtree. So instead of calling them at the end of your function (preorder) like you do now, if you call them earlier (postorder); now you know their L and instead of calling counter, you simply add them up. You visit every node exactly once.
You can completely delete your counter function.
Here is modified code (comments explain the code) :
//helper to check leaves, null nodes are not leaf
bool isLeaf(node* tree){
return (tree && (!tree->right) && (!tree->left));
}
//change return type to catch child node's 'L' value through recursive calls
int updateNode(node*tree) {
if (!tree) return 0; //0 for null, for example tree->right for '24'
if (isLeaf(tree)) tree->L = 0; //All the leaves
int a,b;
//find 'L' for left child into a
if(isLeaf(tree->left)){
if(tree->left->label%2!=tree->label%2) a=1; //this will be true for '24' and '10'
else a=0;
}
else a = updateNode(tree->left);
//Now find 'L' for right child into b
if(isLeaf(tree->right)){ //this will be true for '10'
if(tree->right->label%2!=tree->label%2) b=1;
else b=0;
}
else b = updateNode(tree->right);
//combine them
tree->L = a+b; //this will be true for '20'
return tree->L; //return for parent's sake
}
And driver to run it:
void inorder(node* tree){
if(!tree) return ;
inorder(tree->left);
printf("%d : %d %d\n",tree->label,tree->L,isLeaf(tree) );
inorder(tree->right);
}
int main(int argc, char const *argv[])
{
node* tree = 0;
addnodeBST(tree,20);
addnodeBST(tree,10);
addnodeBST(tree,24);
addnodeBST(tree,17);
addnodeBST(tree,23);
addnodeBST(tree,5);
updateNode(tree);
inorder(tree);
return 0;
}
And..your addnodeBST will fail for equal values. Change the second if to else.

Why does my function(on binary tree) print an unexpected result?

I wanna a make function , which takes as parametrs a binary tree ,t, and two integers a,b and prints how many integers are between a and b...
As example here is a binary tree ,with three nodes and data :
10,15,20.
I call this function for example : between(t ,10 ,20) and as result i expect the number 1 , but this does not happen..
My function is :
`
int between (tree t, int a, int b) {
if (t== NULL)
return 0;
if ((t->data >a ) && ( t->data <b))
return 1 + between(t->left,a,b) + between(t->right,a,b);
}
Can anyone explain me ?
First of all, if the number is not between a and b, you have not defined a return value, which is an error other than your program doesnt do what it is required, but the function doesnt return an int value.
Secondly, you should go on, when the value is not on your range.
Your function should look like this:
int between (tree t, int a, int b) {
if (t== NULL)
return 0;
if ((t->data >a ) && ( t->data <b))
return 1 + between(t->left,a,b) + between(t->right,a,b);
else return between(t->left,a,b) + between(t->right,a,b);
}
Better yet, IF the values on the left are lower than values on the right (search tree) you can make an improvement.
int between (tree t, int a, int b) {
if (t== NULL)
return 0;
if ((t->data >a ) && ( t->data <b))
return 1 + between(t->left,a,b) + between(t->right,a,b);
else if(t->data<a)
return between(t->right,a,b);
else if(t->data>b)
return between(t->left,a,b);
}