I am trying to implement a method that checks whether a given binary search tree is balanced or not within a given tolerance. This is the code that I have so far. I have no ideas further than this. Whoever answers this question, could you please provide an explanation as well? That would be very helpful thank you.
A balanced tree is balanced if for each node in the tree the depth of each nodes children differs by at most some tolerance. given a link BinaryTreeNode and a tolerance, it returns true if root is balanced and false otherwise.
tolerance is the maximum tolerance to decide if the tree is balanced
it returns true if the tree is balanced and false if it is not.
I want it to throw a nullpointerexception if root is == null
and an illegalargumentexception if tolerance is < 0
The problem with my code is that the line
if(computeHeight(root) == -1){
the type computeHeight is not applicable for the arguments
I have a getDepth() method that returns the level that the node is located on
public <T> boolean isBalanced(BinaryTreeNode<T> root, int tolerance) {
// TODO Auto-generated method stub
if(root == null){
throw new NullPointerException();
}
if(tolerance < 0){
throw new IllegalArgumentException();
}
if(computeHeight(root) == -1){
return false;
}
else{
return true;
}
}
public int computeHeight(BinaryTreeNode<T> root){
if(root == null){
return 0;
}
int leftHeight = computeHeight(root.getLeftChild());
if(leftHeight == -1){
return -1;
}
int rightHeight = computeHeight(root.getRightChild());
if(rightHeight == -1){
return -1;
}
int heightDifference = Math.abs(leftHeight - rightHeight);
if(heightDifference > 1){
return -1;
}
else{
return Math.max(leftHeight, rightHeight) + 1;
}
}
Related
I am having trouble finding out if the number of nodes at each level is the same. The question and my code so far is provided below
Two binary trees are called similar sized if the number of nodes is the same at each level of the tree
Given the following:
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
}
The goal of this question is to write a function that will validate if two trees are similar sized.
The function should return true if this is correct and false otherwise
my code:
//implemented with java
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
//function to return size of node, i.e. number of children
int nodeSize() {
//if node has both left and right child node
if (this.rightNode.nodeValue != null && this.leftNode.nodeValue != null) {
return 2;
//if node has no child nodes
} else if (this.rightNode.nodeValue == null && this.leftNode.nodeValue == null) {
return 0;
//if node just has either left or right child node
} else {
return 1;
}
}
boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
//if both nodes have no child nodes
if (firstTree.nodeSize() == 0 && secondTree.nodeSize() == 0) {
return true;
}
//if both nodes have at least 1 child node
if (firstTree.nodeSize() != 0 && secondTree.nodeSize() != 0) {
return ((firstTree.nodeSize() == secondTree.nodeSize()) &&
similarSizedTrees(firstTree.leftNode, secondTree.leftNode) &&
similarSizedTrees(firstTree.leftNode, secondTree.rightNode));
}
//
return false;
}
}
What I am having trouble with is my code does not account for the number of nodes at each level.
Your recursion based approach wouldn't work, because the number of nodes in the next level aren't influenced by which node each child descends from. You could modify your approach to use a simple level order traversal.
(Edit: adding #Piotr's explanation)
The basic idea is to count nodes on each level. In the example picture there is 1 node on level 1, 2 nodes on level 2 and 3 nodes on level 3 and finally 1 node on level 4. These numbers are exactly the same for both tree, even if they are not exactly the same. This algorithm is computing these counts for each level, and if discrepancy is found, it returns False. Otherwise it returns True in the end if both trees are similar. (I'm not well versed in Java, but you can easily translate the algorithm):
def similar(firstTree, secondTree):
queue1, queue2 = queue(firstTree), queue(secondTree) # create queues for traversal
# each queue stores all nodes in a given level
while queue1 and queue2:
if len(queue1)!=len(queue2): # check base condition
return False
i = 0
while i<len(queue1): # append all next level nodes for tree 1
node = queue1.pop()
if node.left:
queue1.insert(node.left)
if node.right:
queue1.insert(node.right)
i += 1
i = 0
while i<len(queue2): # append all next level nodes for tree 2
node = queue2.pop()
if node.left:
queue2.insert(node.left)
if node.right:
queue2.insert(node.right)
i += 1
if queue1 or queue2:
return False # either tree couldn't complete traversal because of different heights
return True
A couple solutions can be found here: https://www.techiedelight.com/check-if-two-binary-trees-are-identical-not-iterative-recursive/
this is the recursive function shown from the link mentioned above tailored to your code.
boolean similarSizedTrees(TreeNode x, TreeNode y) {
// bottom of tree reached
if (x == null && y == null) {
return true;
}
// both trees are non-empty and the value of their root node matches,
// recur for their left and right subtree
return (x != null && y != null) && (x.key == y.key) &&
similarSizedTrees(x.left, y.left) &&
similarSizedTrees(x.right, y.right);
}
EDIT: You could also keep count of the nodes at each level using two global int variables, one for each tree, as you traverse the tree increment each variable, then compare them together before continuing down to the next level.
Here is a solution using recursion:
int find_height(TreeNode t){
return (t == null)? 0 : 1 + Math.max(find_height(t.leftNode), find_height(t.rightNode));
}
boolean is_similar_tree(TreeNode l, TreeNode r){
int l_height = find_height(l);
int r_height = find_height(r);
if(l_height != r_height)
return false;
int[] l_height_sums = new int[l_height];
int[] r_height_sums = new int[r_height];
is_similar_tree_helper(l, l_height_sums, l_height);
is_similar_tree_helper(r, r_height_sums, r_height);
return Arrays.equals(l_height_sums, r_height_sums);
}
void is_similar_tree_helper(TreeNode t, int[] table, int height){
if(t == null || height == 0)
return;
table[height - 1]++;
is_similar_tree_helper(t.leftNode, table, height - 1);
is_similar_tree_helper(t.rightNode, table, height - 1);
}
The idea is to count the number of nodes in each level, then check if the total number of levels of two trees are the same or not. If it is not the same then return false otherwise check each level count and compare the value. If two values are equal then return true otherwise false.
class TreeNode {
String nodeValue;
TreeNode rightNode;
TreeNode leftNode;
TreeNode(String nodeValue, TreeNode rightNode, TreeNode leftNode) {
this.nodeValue = nodeValue;
this.rightNode = rightNode;
this.leftNode = leftNode;
}
public void countLevelNode(TreeNode root, int level, int[] sum) {
if(root == null) return;
sum[level]++;
countLevelNode(root.leftNode, level + 1, sum);
countLevelNode(root.rightNode, level + 1, sum);
}
boolean similarSizedTrees(TreeNode firstTree, TreeNode secondTree) {
int[] countFirstTreeNode = new int[1000];
int[] countSecondTreeNode = new int[1000];
int totalLevelofFirstTree = 0;
int totalLevelofSecondTree = 0;
countLevelNode(firstTree, totalLevelofFirstTree, countFirstTreeNode);
countLevelNode(secondTree, totalLevelofSecondTree, countSecondTreeNode);
if(totalLevelofFirstTree != totalLevelofSecondTree){
return false;
}
else{
for(int i = 0; i < totalLevelofFirstTree; i++){
if(countFirstTreeNode[i] != countSecondTreeNode[i]){
return false;
}
}
return true;
}
}
}
So I have written an implementation of a BST in Java. My goal is to make it balanced aswell, more precisly an AVL tree. I am having some problem though, I don't know how to implement the trinodeRestructering method(ie the method that balances the tree) I have tried various things but these pointers are sometimes difficult to deal with and I am not sure how to do this recursivly. Down below is my code for adding a new element and the method to check if we are more than 2 steps difference in the tree.
add and balancing method:
private TreeNode insert(TreeNode currN, TreeNode newN) {
if (currN == null) {
return newN;
}
if (currN.getData() == newN.getData()) {
throw new IllegalArgumentException("Value already exists.");
}
if (newN.getData() < currN.getData()) {
if (currN.getLeft() == null) {
currN.setLeft(newN);
} else {
insert(currN.getLeft(), newN);
}
} else {
if (currN.getRight() == null) {
currN.setRight(newN);
} else {
insert(currN.getRight(), newN);
}
}
if (needBalancing()) {
trinodeRestructering(currN);
}
return currN;
}
private TreeNode trinodeRestructering(TreeNode currN) {
//Not sure what to do here.
return currN;
}
height checking method.
public boolean needBalancing(){
if(height(root) == -1){ // true if we need to balance
return true;
}else{
return false;
}
}
private int height(TreeNode node){
if (node == null)
return 0;
int left = height(node.getLeft());
int right = height(node.getRight());
if (left == -1 || right == -1)
return -1;
if (Math.abs(left - right) > 1) {
return -1;
}
return Math.max(left, right) + 1;
}
I might add that I got an working inOrder method, perhaps I could use it to balance my tree?
Here is my code to find position of a certain element. And I am using Binary tree to store my Dictionary I want to know why it shows warning for Comparable-type. I have to use this in my project where element is a string type.
public int get(Comparable element){
return getPosition(element,root);
}
private int getPosition(Comparable element, TreeNode root){
int count = 0;
if (root == null){
return -1;
}else{
Stack t = new Stack();
t.push(root);
while(!t.empty()){
TreeNode n = (TreeNode)t.pop();
if(element.compareTo(n.value)==0){
return count;
}else{
if(n.getLeftTree()!=null){
t.push(n.getLeftTree());
count++;
}
if (n.getRightTree()!= null){
t.push(n.getRightTree());
count++;
}
}
}
return -1;
}
}
The java generic typing parameters are missing <...>.
public int get(Comparable<?> element){
return getPosition(element, root);
}
private int getPosition(Comparable<?> element, TreeNode root) {
int count = 0;
if (root == null) {
return -1;
} else {
Stack<TreeNde> t = new Stack<>();
t.push(root);
while (!t.empty()) {
TreeNode n = t.pop();
if (element.compareTo(n.value) == 0) {
return count;
} else {
if (n.getLeftTree() != null) {
t.push(n.getLeftTree());
count++;
}
if (n.getRightTree() != null) {
t.push(n.getRightTree());
count++;
}
}
}
}
return -1;
}
However the algorithm seems not to be counting the leftish part of the tree upto the found element. However if position is not the index in the sorted elements, that might be okay. (I did not check the correctness, as there is no early < check.) If this was a home work assignment, "non-recursive with stack," rework a recursive version. Probably two nested loops, and a comparison on -1 and +1.
Many answers on the net for 'finding Least Common Ancestor in binary tree' and its supplementary question 'find distance between 2 nodes' have 4 issues:
Does not consider duplicates
Does not consider if input node is invalid/absent/not in tree
Use extra / aux storage
Not truncating the traversal although answer is obtained.
I coded this sample to overcome all handicaps. but since I did not find 'a single' answer in this direction, I would appreciate if my code has a significant disadvantage which I am missing. Maybe there is none. Additional eyeballs appreciated.
public int distance(int n1, int n2) {
LCAData lcaData = new LCAData(null, 0, 0);
int distance = foundDistance (root, lcaData, n1, n2, new HashSet<Integer>());
if (lcaData.lca != null) {
return distance;
} else {
throw new IllegalArgumentException("The tree does not contain either one or more of input data. ");
}
}
private static class LCAData {
TreeNode lca;
int count;
public LCAData(TreeNode parent, int count) {
this.lca = parent;
this.count = count;
}
}
private int foundDistance (TreeNode node, LCAData lcaData, int n1, int n2, Set<Integer> set) {
assert set != null;
if (node == null) {
return 0;
}
// when both were found
if (lcaData.count == 2) {
return 0;
}
// when only one of them is found
if ((node.item == n1 || node.item == n2) && lcaData.count == 1) {
// second element to be found is not a duplicate node of the tree.
if (!set.contains(node.item)) {
lcaData.count++;
return 1;
}
}
int foundInCurrent = 0;
// when nothing was found (count == 0), or a duplicate tree node was found (count == 1)
if (node.item == n1 || node.item == n2) {
if (!set.contains(node.item)) {
set.add(node.item);
lcaData.count++;
}
// replace the old found node with new found node, in case of duplicate. this makes distance the shortest.
foundInCurrent = 1;
}
int foundInLeft = foundDistance(node.left, lcaData, n1, n2, set);
int foundInRight = foundDistance(node.right, lcaData, n1, n2, set);
// second node was child of current, or both nodes were children of current
if (((foundInLeft > 0 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInRight > 0) ||
(foundInCurrent == 1 && foundInLeft > 0)) &&
lcaData.lca == null) {
// least common ancestor has been obtained
lcaData.lca = node;
return foundInLeft + foundInRight;
}
// first node to match is the current node. none of its children are part of second node.
if (foundInCurrent == 1) {
return foundInCurrent;
}
// ancestor has been obtained, aka distance has been found. simply return the distance obtained
if (lcaData.lca != null) {
return foundInLeft + foundInRight;
}
// one of the children of current node was a possible match.
return (foundInLeft + foundInRight) > 0 ? (foundInLeft + foundInRight) + 1 : (foundInLeft + foundInRight);
}
The algorithm appears to be (without pulling it apart entirely) to exhaustively traverse the entire tree until a node is found where there is one node found on the left and one on the right. And creating an additional set as you go.
The problem here seems to be that your algorithm is very inefficient. That may fit your requirements, if this particular operation is almost never carried out. But normally you could do better.
I have written the below code for recursively searching binary tree .
Even though my system.out statement is getting executed , the return statement is not returning out of entire recursion and thus this method not returning true.
Can anyone suggest how can I return out of entire recursion.?
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
if (root != null)
{
int rootVal = root.getData();
BinaryTreeNode left = root.getLeft();
BinaryTreeNode right = root.getRight();
if (left != null)
{
isElementinTree(num,left);
}
if (right != null)
{
isElementinTree(num,right);
}
if (num == rootVal)
{
System.out.println("------ MATCH -----");
return true;
}
}
return false;
}
This is the problem:
if (left != null)
{
isElementinTree(num,left);
}
if (right != null)
{
isElementinTree(num,right);
}
You're calling the method in those cases - but ignoring the result. I suspect you just want to change each of those to return immediately if it's found:
if (left != null && isElementinTree(num, left))
{
return true;
}
if (right != null && isElementinTree(num, right))
{
return true;
}
Or to make the whole thing more declarative, you can do it more simply:
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
return root != null && (root.getData() == num ||
isElementInTree(num, root.getLeft()) ||
isElementInTree(num, root.getRight()));
}
It's fine to call isElementInTree with a null second argument, as you're already protecting against that with the first part.
What is wrong with a simple solution like this:
public static boolean isElementinTree(int num, BinaryTreeNode root)
{
return root != null && //The tree is non-null
(num == root.getData() || //We have num in this node OR
isElementInTree(num, root.getLeft()) || //We have num in left subtree OR
isElementInTree(num, root.getRight()) ); //We have num in right subtree
}
You need to check if the value is in one of the branches, and save that result.
Initialize a variable boolean found = false;.
When you do the recursive call, you need to do something like:
found = isElementinTree(num,left)
same thing for the right side.
At the end, instead of returning false, check if the value was found on a branch, simply return found;
Also, first check if the number you are looking for isn't on the Node itself, instead of searching each branch first. Simply switch the order of the if's.
If you do find the element you're looking for in the left or right subtrees you need to return this fact back up to the caller:
if (left != null)
{
if(isElementinTree(num,left)) return true;
}
if (right != null)
{
if(isElementinTree(num,right)) return true;
}
Only if you find it in none of the left tree, right tree and current node do you eventually fall through to the final return false.
Recursion solution:
boolean isElementinTree (int num, BinaryTreeNode root)
{
if(root == null)
return false;
if(root.value == num)
return true;
boolean n1 = isElementinTree(num,root.getLeft());
boolean n2 = isElementinTree(num,root.getRight());
return n1 ? n1 : n2;
}