Two versions of counting leaves in a Tree - java

What's the difference between these two versions?
public static int countLeaves(IntTreeNode root) {
if (root == null) {
return 0;
} else
return 1 + countLeaves(root.left) + countLeaves(root.right);
}
public static int countLeaves(IntTreeNode root) {
if (root == null) {
return 0;
} else if (root.left == null && root.right == null) {
return 1;
} else
return countLeaves(root.left) + countLeaves(root.right);
}
I couldn't find anything that use the first version in the internet.
Is the first version wrong?
I have tried to trace them on paper, they seem to be the same.
But I just want to be sure.

The first seems to count all nodes in a tree, whereas the second one one counts all leafs.
Indeed in the first one, the recursion stops when there is no valid tree anymore (root == null) and it always goes into recursion checking the left and right tree by adding 1 (for the current node).
The second only counts the leafs using the condition if (root.left == null && root.right == null).
That's assuming a leaf is identified as node that has a null root.left and a null root.right.

The first version is not counting leaves - it's counting nodes.
The second version is indeed counting leaves.
These methods will not return the same result, here's an example:
root(5)
/ \
leaf(3) leaf(7)
for such a tree the first method will return 3 (number of nodes) and the second one will return 2 (number of leafs).

Related

Conditionally counting nodes in a tree traversal - recursively

Working on a University assignment which requires comparing nodes in a tree and making a count of nodes which meet a certain condition. I can see how I could do this iteratively, traversing the tree with a stack etc, but I'm certain the lecturers are looking for a recursive solution and I'm struggling to wrap my head around this particular implementation.
My current (flawed) implementation is:
public int traverseIncrement(User user, User reference) {
if(user == null)
return 0;
int count = 1;
if (user.getLeft() != null) {
if(user.getLevel() > reference.getLevel()) {
count += traverseIncrement(user.getLeft(), reference);
}
}
if (user.getRight() != null) {
if(user.getLevel() > reference.getLevel()) {
count += traverseIncrement(user.getRight(), reference);
}
}
return count;
}
There are two obvious problems, the first being that the first node is never evaluated and the second being that I am always one higher than the required output. Any nudge in the right direction would be helpful!
I think the two problems are related. Rather than assume the count is 1 then recurse depending upon whether the condition is met, you should set count depending upon the condition, then recurse. In other words, leave the evaluation of a given node up to the call that is handling that node.
Also, you can eliminate the check for left or right being null since your function already checks on entry.
public int traverseIncrement(User user, User reference) {
if(user == null)
return 0;
int count = (user.GetLevel() > reference.getLevel()) ? 1 : 0;
count += traverseIncrement(user.getLeft(), reference);
count += traverseIncrement(user.getRight(), reference);
return count;
}

Can someone explain this if-loop for a method to delete negatives in a linear list?

this method allows to delete all negatives in a linear list. I marked the if-loop which i don´t understand 100%.
So this method travers over the whole list. The rest of the code makes total sense. But the only problem i have is why is head = n.next when prev == null ?
Is this because there are two "spaces" now and that is not allowed? (two spaces because prev = null and n must also be null because it jumped in the if loop for a negative)
ListNode prev = null;
ListNode n = head;
while (n != null) {
if (n.val < 0) {
if (prev == null) { //this if- loop i don´t understand
head = n.next;
}
else {
prev.next = n.next;
}
}
else {
prev=n;
n = n.next;
}
}
First of all if is not a loop it is a statement used for conditional branching.
So, starting from if (n.val < 0), you check if the current element is less then zero, if it is you check if the element before the current element is null. If it is, that means that your current element is the head of the list, and it's value is less then zero, so you want to delete it. So what you have to do is only make the head of the list the element after the current head.
So the purpose of if (prev == null){ is to check if the current element (which is less then zero) is the head of the list, so you could know how to remove it.
Moving on, if the current element is not the head of the list, you would just say that the element after the previous one (relative to current) is the one after the current, so the less then zero element is no longer in the list.

How to insert a node into a complete binary tree in Java?

As we all know, when inserting into a complete binary tree we have to fill all the children for all the leafs from left to right. I have the following method that inserts a node into a complete binary tree.
//fields
private T item;
private int size;
private CBTree<T> left, right;
//add method
public void add(T item)
{
if(left == null)
{
left = new CBTree<T>(item);
size += left.size;
}
else if(right == null)
{
right = new CBTree<T>(item);
size += right.size;
}
else if(!((left.left != null) && (left.right != null)) &&
((right.left == null) || (right.right == null)))
{
left.add(item);
}
else
{
right.add(item);
}
}
The problem with this implementation is that after the 11th node it adds the 12th node to the left child of 8 instead of 6. I understand that this is happening because the following line is reassigning the root of this tree to be the left child of the root.
left.add(item);
So it is changing the root to 2. Is there a way to change the root back to its original value? I am trying to accomplish this without using stacks and queues.
It's not sufficient to just check children of children to determine which side to go to, because as soon as the tree reaches height 4 that won't work any more, since children of children of the root won't change from that point forward yet we can still go either left or right.
2 approaches come to mind:
Have a complete variable at each node.
A node with no children is complete.
A node with 2 complete children of equal size is complete.
Whenever update the tree (insert or delete) you update this variable for each affected node as well.
Mathematically determine whether a subtree is complete based on the size.
A tree of size 2^n - 1 is complete (for some n).
Note: this will only work if we're not allowed to freely delete elements without keeping the tree complete.
For either approach, when doing an insertion, we go left (left.add(item)) if either of these conditions are true:
the left subtree is not complete
the left and right subtrees are of the same size (both complete, meaning we're increasing the height with this insertion)
I'll leave the implementation details to you.
Note: you need to also update size when doing left.add(item); and right.add(item);. You could probably just stick a size++ in the add function, since we're adding 1 element so size increases by 1 no matter what.
Thanks to Dukeling's answer, the correct way to implement the method was to mathematically determine if the subtree was full. Here is the code:
//fields
private T item;
private int size;
private CBTree<T> left, right;
//add method
public void add(T item)
{
if(left == null)
{
left = new CBTree<T>(item);
}
else if(right == null)
{
right = new CBTree<T>(item);
}
else if(leftFull())
{
right.add(item);
}
else
{
left.add(item);
}
size++;
}
//Checks if the left subtree is full
public boolean leftFull()
{
int used, leafs = 1;
while(leafs <= size + 1)
{
leafs *= 2;
}
leafs /= 2;
used = (size + 1) % leafs;
if(used >= (leafs / 2))
{
return true;
}
else
{
return false;
}
}

Recursion related to trees

Here's code which finds a root-to-leaf path that equals to a particular sum:
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left==null && root.right==null) {
return (sum == root.val);
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
Even when one recursive call returns true (with return (sum==root.val)), I don't understand how the original function call is true.
My understanding is that in the stack, that particular activation record is true, but then wouldn't the other calls on the stack return false; clearly the remaining might not be a path, and wouldn't that render it all as false? How does it attach importance to that if statement?
This is actually not coded in the clearest manner.
Recursion is always about solving a problem by using the same procedure (function) to solve one or more smaller versions of the same problem, then combining these solutions.
In this case, the smaller problems are to check for the rest of the required sum in the left and right subtrees (if they exist).
We can stop after the left if successful, skipping the right. In this manner, the "leftmost" path in the tree with the desired sum is found. We have no need to find any others.
When checking a subtree, we subtract the value of the current node from the desired sum. Intuitively this is making the problem "smaller" as described above.
I'll add comments that show the logic.
public boolean hasPathSum(TreeNode root, int sum) {
// If we've reached a null child, the other child is non-null, so we're
// not at a leaf, so there no way this can be a leaf-to-path sum.
// See below for why this is the case.
if (root == null) {
return false;
}
// If we're at a leaf (null children), then we've found the path
// if and only if the node value exactly equals the sum we're looking for.
if (root.left == null && root.right == null) {
return (sum == root.val);
}
// We're not at a leaf. See if we can find the remaining part of the sum
// by searching the children. Null children are handled above. If the
// sum is found in the left subtree, the short-circuit evaluation of ||
// will skip searching the right.
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
Note that it possibly doesn't make sense that
hasPathSum(null, 0)
returns false in this code. I'd do it this way:
class TreeNode {
// ... skipping other TreeNode fields.
public boolean isLeaf() { return left == null && right == null; }
public boolean hasPathSum(int sum) {
return isLeaf() ? sum == val :
(left != null && left.hasPathSum(sum - val)) ||
(right != null && right.hasPathSum(sum - val);
}
}
Here is a good visualisation for recursion. Basically, when you call hasPathSum it 1st checks if root is null. If it's null, then it will return with a false.
If root is not null, then it goes further. if left and right both nulls then you are at a leaf node. If the leaf node has the same value as the root, then you'll return with true. Otherwise it will be a false.
If both if statements were skipped it means, that either the left, or the right (or both) has more nodes. Then the root node will become the your left and right, and you'll check for the sum value there, and return with the result from them.
Let's assume that this is your tree and the leaf4 has the desired value:
root
left right
leaf1 - leaf3 leaf4
----------- 1st depth, with root node ---------------
hasPathSum(root)
root==null //false, so it moves on
root.left // is 'left', so skipping
hasPathSum(left) || hasPathSum(right) // this statement will be evaluated
------------- 2nd depth, with left node ---------------
hasPathSum(left)
left==null //false, so it moves on
left.left // is 'leaf1', so skipping
hasPathSum(leaf) || hasPathSum(null) // this statement will be evaluated
------------- 3rd depth, with leaf1 node ---------------
hasPathSum(leaf1)
leaf1==null //false, so it moves on
leaf1.left and leaf1.right // are both null, so returnin with sum == root.val
------------- 3rd depth, with - node ---------------
hasPathSum(-)
-==null //true, so it returns with false
------------- 2nd depth, with left node ---------------
false || false // is false, so it will return with false
------ in this moment, hasPathSum(left) part of 1st depth's has been evaulated to false
so hasPathSum(right) has to be ecaluated as well.
It wont be any different from the code above, except that when processing leaf4, the sum==root.val will be true, so the whole thing will return true. Hope this helps.
A simple example explained might help.
Let's consider a tree like this:
5
/ \
2 3
\
1
And we're looking for a sum of 9.
Now the recursive calls will look like this:
(my indentation is such that each statement is executed by the function at the previous level of indentation)
hasPathSum(N5, 9)
hasPathSum(N2, 9-5 = 4)
return false // since 2 != 4
hasPathSum(N3, 9-5 = 4)
hasPathSum(null, 4-3 = 1) // left child of N3
return false // since root == null
hasPathSum(N1, 4-3 = 1)
return true // since 1 == 1
return (false || true) = true
return (false || true) = true

how to go the middle of the singularly linked list in one iteration?

Recently I have been asked one question that in a singularly linked list how do we go to the middle of the list in one iteration.
A --> B --> C --> D (even nodes)
for this it should return address which points to B
A --> B --> C (odd nodes)
for this also it should return address which points to B
There is one solution of taking two pointers one moves one time and other moves two times but it does not seem working here
LinkedList p1,p2;
while(p2.next != null)
{
p1 = p1.next;
p2 = p2.next.next;
}
System.out.print("middle of the node" + p1.data); //This does not give accurate result in odd and even
Please help if anyone has did this before.
The basic algorithm would be
0 Take two pointers
1 Make both pointing to first node
2 Increment first with two node and first if its successful then traverse second to one node ahead
3 when second reaches end first one would be at middle.
Update:
It will definitely work in odd case, for even case you need to check one more condition if first point is allowed to move next but not next to next then both pointers will be at middle you need to decide which to take as middle
You can't advance p1 unless you successfully advanced p2 twice; otherwise, with a list length of 2 you end up with both pointing at the end (and you indicated even length lists should round toward the beginning).
So:
while ( p2.next != null ) {
p2 = p2.next;
if (p2.next != null) {
p2 = p2.next;
p1 = p1.next;
}
}
I know you've already accepted an answer, but this whole question sounds like an exercise in cleverness rather than an attempt to get the correct solution. Why would you do something in O(n) when you can do it in O(n/2)?
EDIT: This used to assert O(1) performance, and that is simply not correct. Thanks to ysth for pointing that out.
In practice, you would do this in zero iterations:
LinkedList list = ...
int size = list.size();
int middle = (size / 2) + (size % 2 == 0 ? 0 : 1) - 1; //index of middle item
Object o = list.get(middle); //or ListIterator it = list.listIterator(middle);
The solution of taking two pointers and one moves a half the rate should work fine. Most likely it is not the solution but your actual implementation that is the problem. Post more details of your implementation.
static ListElement findMiddle(ListElement head){
ListElement slower = head;
ListElement faster = head;
while(faster.next != null && faster.next.next !=null ){
faster = faster.next.next;
slower = slower.next;
}
return slower;
}
public static Node middle(Node head){
Node slow=head,fast=head;
while(fast!=null& fast.next!=null && fast.next.next!=null){
slow=slow.next;
fast=fast.next.next;
}
if(fast!=null && fast.next!=null){
slow=slow.next;
}
return slow;
}
public ListNode middleNode(ListNode head) {
if(head == null) return head;
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}

Categories