Non recursive floor method for Binary search tree - java

I have been trying to get this to work but while it works for majority of the input sometimes it gives the wrong output. I have spent some time debugging the code and it seems the problem is when i get a Node that is smaller than the root but bigger than the left node under the root.
How can I traverse the right sub-tree and still return the right key if no node in the right sub-tree is the floor node for that key?

Recall that if you do anything recursively, it can be transformed* into iteration.
Let's consider taking the floor of a well-formed BST, which should simply be the smallest element which is less than or equal to your key in the tree. All we have to do is traverse the tree to get it.
Let's implement it recursively so we can tease out a few important corollaries between iteration and recursion.
// Assuming non-null root node with method declaration
private Node floor(Node root, Key key, Node lowestNode) {
if(key.compareTo(root.getKey()) <= 0) {
if(root.getLeft() != null) {
return floor(root.getLeft(), key, lowestNode);
} else {
return root.compareTo(lowestNode) < 0 ? root : lowestNode;
}
} else {
if(root.getRight() != null) {
lowestRightNode.add(root);
return floor(root.getRight(), key, lowestNode);
} else {
return lowestNode;
}
}
Let's walk through the conditions for success.
If we compare a node to be less than or equal to our key value:
If we have a left child, there's something smaller. Traverse down the left half of the tree.
Otherwise, we're at the floor - which means we're at the node whose value is less than or equal to our key. Return it.
Otherwise (our node has a value greater than our key):
If we have a right child, there's a chance that our work isn't done yet (something's smaller). We'd like to keep it around since we could step off of the tree, so let's store it, then traverse down the right half of the tree.
Otherwise, we've fallen off of the tree. Return the smallest element we've kept track of.
An example may look something like this:
9
/ \
3 14
/ \
1 2
With a key of 12:
Compare with 9. We're larger. Store 9 in our lowest node variable, recurse right.
Compare with 14. We're smaller, but we don't have a left child. We compare the value 14 to 9 and 9 is smaller, so we return the node with 9.
If we want to convert this into iteration, then think about your starting point, your conditional check, and your incrementation steps.
Starting point: A non-null node
Conditional check:
key.compareTo(root.getKey()) <= 0
root.getLeft() != null
continue
root.compareTo(lowestRightNode) < 0 ? root : lowestRightNode
terminal
else
root.getRight() != null
store temp value and continue
return lowestRightNode
terminal
Pay close attention to your continuation conditions, and what other work you'd have to do to keep track of the lowest node you've seen so far (only for the right-hand side, that is).
*: Some recursive operations are more painful to convert than others, of course.

Related

Delete duplicate value in linked list (Recursion in Java)

I need to return the head of the linked list with all the duplicate elements deleted. I understand the logic of the problem, but I am getting confused in using recursion.
/*
Node is defined as
class Node {
int data;
Node next;
}
*/
Node RemoveDuplicates(Node head) {
if ((head == null) || (head.next == null))
return head;
else {
RemoveDuplicates(head.next);
if (head.data==head.next.data) head.next = head.next.next;
}
return head;
}
If I call the function RemoveDuplicates(head.next) before the if condition; it works fine. However if I swap the order of the statements (rest everything is exactly the same)like:
if (head.data==head.next.data) head.next = head.next.next;
RemoveDuplicates(head.next);
the code is unable to correctly solve for a test case like '1->1->1->1'. The output I get in the latter case is '1->1'.
I would really like some suggestions on how I could understand recursion better.
Firstly, your code does only solve if the list is in order, it cannot remove all duplicated node if data in random position, ex: 1, 2, 3, 1, 1, 2, 3
Secondly, for your concern, you can think it like below:
Case 1:
RemoveDuplicates(head.next);
if (head.data==head.next.data) head.next = head.next.next;
You check from element right before the end of the list, compare its data and the next data, if matched, replace the next node by the next next node. Then, jump to the previous node and repeat.
Case 2:
if (head.data==head.next.data) head.next = head.next.next;
RemoveDuplicates(head.next);
You begin with the first node, check if it duplicate with the next node. If duplicated, bring the 3th node to replace the 2nd node. The, jump to the next node (now is the original 3rd node) to check if it duplicate to the next node. You see, you miss checking the 1st node and the original 3rd node.
I think you should try mode debug to understand deeply about this.
BTW, try to apply convention to your code. J
Hope this help!
The problem is that you "skip" some nodes in the latter case.
Let's name the nodes in your example to see what's happening:
v
1 -> 1 -> 1 -> 1
a b c d
v indicates the current reference of head in your method.
If you now do a check first, you compare a and b, then remove b:
v
1 -> 1 -> 1
a c d
Then you do a recursion step, which travels forward one node to c:
The problem is that you "skip" some nodes in the latter case.
Let's name the nodes in your example to see what's happening:
v
1 -> 1 -> 1 -> 1
a b c d
v indicates the current reference of head in your method.
If you now do a check first, you compare a and b, then remove b:
v
1 -> 1 -> 1
a c d
And here's your problem. You never compared c to a value to its left, i.e. a/c or b/c.
This problem doesn't occur when switching the lines because that way you're walking the other way, i.e. you go through your list bottom-up (right to left) and only compare/delete to the right ("behind you" in walking direction).

Lowest value path in a binary search tree

Was asked this in an interview recently and got stumped.
Given a binary tree where the nodes contain integer values, find the path (going all the way down to the leaves) that sum up to the lowest value.
So starting at root and traversing all the way down in a depth first fashion until you get to a leaf and adding up the node values along the way. Repeat for every possible path to the leaves.
I was just overwhelmed by the amount of possibilities there could be. But i tried doing a dfs, adding up values along the way, until i got to a leaf. Stored the path and the sum in a hashmap. But then I couldn't figure out how to reset the current sum and go down a different path to a different leaf the second time around.
It could be solved along these lines: Imagine that we define the function lowestValuePath(path, currentValue, bst) which takes a path as a string representation ("lrlrr" would be equivalent to having gone left, right, left, right, right), a value which is the currently accumulated sum of node values along this path, and bst which is the tree to traverse.
Our starting case would be lowestValuePath("", 0, rootNode), and termination would occur on a leaf, returning the path traversed and the value accumulated along this path.
Java-ish pseudo code could be:
TraverseResult {
String path;
int value;
}
TraverseResult lowestValuePath(path, currentValue, bst) {
val newValue = currentValue + bst.getNodeValue();
if bst.isLeaf():
return new TraverseResult(path, newValue);
else
val rightPath = lowestValuePath(path + "r", newValue, bst.getRightNode());
val leftPath = lowestValuePath(path + "l", newValue, bst.getLeftNode());
return leftPath < rightPath ? leftPath : rightPath
}
Some special case handling for the empty tree might be necessary..
If it is a "Binary Search Tree", then for every node T:
left(T) <= T <= right(T)
So actually just turn left all the time and you will get to the lowest value.

What is the big oh for comparing two binary trees?

If one binary tree has x nodes and the other has y nodes where x is bigger than y. I was thinking O(n2) because searching for each node is O(n).
And how about inserting then comparing the trees?
Assuming your binary trees are sorted, this is an O(n) operation (where n is the sum of the nodes in both trees, not the product).
You can simply run two "indexes" side by side through the trees stopping when an element is different. If you get to the end of both and no differences were found, then the trees were identical, something like the following pseudo-code:
def areEqual (tree1, tree2):
pos1 = first (tree1)
pos2 = first (tree2)
while pos1 != END and pos2 != END:
if tree1[pos1] != tree2[pos2]:
return false
pos1 = next (tree1, pos1)
pos2 = next (tree2, pos2)
if pos1 != END or pos2 != END:
return false
return true
If they're not sorted, and you have no other information that may allow you to optimise the function, and cannot use extra data structures, it will be O(n2), since you'll have to find an arbitrary equal node in the second tree for every single node in the first (as well as mark it somehow to indicate you've used it).
Keep in mind there are usually ways to trade space for time if the former is more important (and it often is).
For example, even with totally unordered trees, you can reduce the complexity considerably by using hashing for example:
def areEqual (tree1, tree2):
hash = []
# Add all items from first tree.
for item in tree1.allItems():
if not exists hash[item]
hash[item] = 0
hash[item] += 1
# Subtract all items from second tree.
for item in tree2.allItems():
if not exists hash[item]
hash[item] = 0
hash[item] -= 1
if hash[item] == 0:
delete hash[item]
if hash.size != 0:
return false
return true
Since hashing tends to amortise toward O(1), the problem as a whole can be considered O(n).

Depth of a Node in BST including duplicates

i have implemented a function to find the depth of a node in a binary search tree but my implementation does not take care of duplicates. I have my code below and would like some suggestions on how to consider duplicates case in this function. WOuld really appreciate your help.
public int depth(Node n) {
int result=0;
if(n == null || n == getRoot())
return 0;
return (result = depth(getRoot(), n, result));
}
public int depth(Node temp, Node n, int result) {
int cmp = n.getData().compareTo(temp.getData());
if(cmp == 0) {
int x = result;
return x;
}
else if(cmp < 0) {
return depth(temp.getLeftChild(), n, ++result);
}
else {
return depth(temp.getRightChild(), n, ++result);
}
}
In the code you show, there is no way to prefer one node with same value over another. You need to have some criteria for differentiation.
You can retrieve the list of all duplicate nodes depths using the following approach, for example:
Find the depth of your node.
Find depth of the same node for the left subtree emerging from the found node - stop if not found.
Add depth of the previously found node (in 1) to the depth of the duplicate
Find depth of the same node for the right subtree emerging from the found node (in 1) - stop if not found.
Add depth of the previously found node (in 1) to the depth of the duplicate
Repeat for left and right subtrees.
Also see here: What's the case for duplications in BST?
Well, if there's duplicates, then the depth of a node with a given value doesn't make any sense on its own, because there may be multiple nodes with that value, hence multiple depths.
You have to decide what it means, which could be (not necessarily an exhaustive list):
the depth of the deepest node with that value.
the depth of the shallowest node with that value.
the depth of the first node found with that value.
the average depth of all nodes with that value.
the range (min/max) of depths of all nodes with that value.
a list of depths of all nodes with that value.
an error code indicating your query made little sense.
Any of those could make sense in specific circumstances.
Of course, if n is an actual pointer to a node, you shouldn't be comparing values of nodes at all, you should be comparing pointers. That way, you will only ever find one match and the depth of it makes sense.
Something like the following pseudo-code should do:
def getDepth (Node needle, Node haystack, int value):
// Gone beyond leaf, it's not in tree
if haystack == NULL: return -1
// Pointers equal, you've found it.
if needle == haystack: return value
// Data not equal search either left or right subtree.
if needle.data < haystack.data:
return getDepth (needle, haystack.left, value + 1)
if needle.data > haystack.data:
return getDepth (needle, haystack.right, value + 1)
// Data equal, need to search BOTH subtrees.
tryDepth = getDepth (needle, haystack.left, value + 1)
if trydepth == -1:
tryDepth = getDepth (needle, haystack.right, value + 1)
return trydepth
The reason why you have to search both subtrees when the values are equal is because the desired node may be in either subtree. Where the values are unequal, you know which subtree it's in. So, for the case where they're equal, you check one subtree and, if not found, you check the other.

Split a binary tree

I am trying to split a binary search tree at the root in Java. I have no idea how to go about this. The recursive call is what is mostly confusing me. Below is the pseudocode that I was given. When x is greater than T (the tree to be split), am I going to call split(R.key, R.right, L, R)? Am I on the right track? This is the only function in the project that is confusing me.
Thanks in advance.
void split( int x, bst T, bst L, bst R) /* assuming x is not in T */
{
if T is null, make L and R null
else if x < T.key
set R = T /* all keys at the root and in right subtree are greater than x */
recursively split T's left subtree into L and R’s left subtree
/* some keys in T's left subtree are greater than x, other may be less than x */
else /* x is greater than T.key */
set L = T
recursively split T's right subtree into L's right subtree and R
}
It is important that you must have a binary ordered tree, such that Left < Root < Right for every subtree. Also, there is no node in the left subtree such that node > Root, and no node in the right subtree such that node < Root. Balancing (that all subtrees are same depth +- 1) is not needed.
It is like a dicomotical search; if the value to split by is greater than your current root, you are sure that it is greater than all nodes in the left subtree (because of the previous restriction). So, in order to search which of the nodes of the tree are bigger, you only need to check the nodes to the right. Likewise, if the value to split by is less than the value of root, it is also less than the values of all the nodes of the right subtree, and you must check more finely in the left tree.
In order to see it clearly, I suggest you to draw this tree (no spacing here)
8
4 12
3 6 10 14
1 2 5 7 9 11 13 15
, set several sample split values, and mark which nodes would remain in the new tree.

Categories