Test if two binary trees are equal - java

I know this may be a duplicate post, but I would submit my own code to your attention.
I wrote the following recursive procedure, but I would like to optimize it.
I would like to stop the treeCompare method as soon as I find a node different from other, instead of comparing all nodes.
Thanks in advance for your help.
This is my thin Node class:
public class Node {
public Node father;
public Node left;
public Node right;
}
And this is my comparator method:
private boolean treeCompare(Node firstNode, Node secondNode) {
if (firstNode == null && secondNode == null)
return true;
else if (firstNode == null || secondNode == null)
return false;
boolean isLEquals = treeCompare(firstNode.left, secondNode.left);
boolean isREquals = treeCompare(firstNode.right, secondNode.right);
return firstNode.equals(secondNode) && isLEquals && isREquals;
}

private boolean treeCompare(Node firstNode, Node secondNode) {
if (firstNode == secondNode)
return true;
if (firstNode == null || !firstNode.equals(secondNode))
return false;
return treeCompare(firstNode.left, secondNode.left) && treeCompare(firstNode.right, secondNode.right);
}

Related

Java test two binary trees are the same

Update:
The best solution should be:
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null) return true;
if(p==null||q==null) return false;
return isSameTree(p.left, q.left)&&isSameTree(p.right, q.right)&&(p.val==q.val);
}
Update:
Thank you all, I know those other solutions you told me, but my question is that why my solution doesn't work. Is it because that I ignore some return values? Thank you!
I have written a code for determining whether two binary trees are the same, I used recursive method to search through the tree, but this code sometimes didn't work, could you please help me to figure it out?
Thanks a lot!
Here's the code:
/*Definition for a binary tree node.
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
*/
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p!=null){
if(q!=null&&p.val==q.val){
isSameTree(p.left, q.left);
isSameTree(p.right, q.right);
}
else return false;
}else{
if(q!=null) return false;
}
return true;
}
Input:
[10,5,15]
[10,5,null,null,15]
Output:
true
Expected:
false
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p!=null){
if(q!=null&&p.val==q.val){
if(!isSameTree(p.left, q.left)) return false;
if(!isSameTree(p.right, q.right)) return false;
return true;
}
else return false;
}else{
if(q!=null) return false;
}
return true;
}
I'm assuming you have a get method to retrieve data.One way you can solve is to let isSameTree methods to accept null values and then compare.
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == q) {
return true;
}
if (p == null || q == null) {
return false;
}
return p.get().isSameTree(q.get()) &&
isSameTree(p.left(), q.left()) &&
isSameTree(p.right(), q.right());
}
Another way is the following:
public boolean isSameTree(TreeNode p, TreeNode q)
{
if (p == null && q == null)
return true;
if (p != null && q != null)
return (p.get == q.get
&& isSameTree(p.left, q.left)
&& isSameTree(p.right, q.right));
return false;
}
You are just calling isSameTree for the child trees, but not checking their return values. Concise and correct version:
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == q) { //Will accept null == null
return true;
}
return p != null && q != null && p.val == q.val &&
isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
Also, #duffymo was incorrect stating you needed to use .equals() instead of ==. You are comparing the val's, which are primitives.
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null)
return true;
if (p != null && q != null)
return (p.val == q.val
&& isSameTree(p.left, q.left)
&& isSameTree(p.right, q.right));
return false;
}
}

Check if two trees are identical

I've made my own Tree class and I trying to check if two trees are identical. But the problem here is I'm using this call :
Tree myTree = new Tree();
Tree mySecondTree = new Tree();
myTree.isIdentical(myTree, mySecondTree);
It's kind of odd to pass it this way, I want to pass it this way :
myTree.isIdentical(mySecondTree);
isIdentical function :
class Tree<T>{
T data;
Tree left;
Tree right;
Tree(T data){
this.data = data;
}
public boolean isIdentical(Tree t1, Tree t2){
if(t1 == t2)
return true;
if(t1==null || t2==null)
return false;
return (
(t1.data == t2.data) &&
(isIdentical(t1.left, t2.left)) &&
(isIdentical(t1.right, t2.right))
);
}
}
I tried using Stack, but I'm kind of stuck on this
Since you want to execute it this way
myTree.isIdentical(mySecondTree);
You could do this
public boolean isIdentical(Tree t2){
Tree t1 = this;
return isIdentical(t1, t2);
}
private boolean isIdentical(Tree t1, Tree t2){
if(t1 == t2)
return true;
if(t1==null || t2==null)
return false;
return (
(t1.data == t2.data) &&
(isIdentical(t1.left, t2.left)) &&
(isIdentical(t1.right, t2.right))
);
}
Your data-structure allows you to call the modified isIdentical(Tree<T>) method in the left and right child nodes after a few checks. Remember that the parent, right-child and left-child are all different Tree node instances in your code.
public boolean isIdentical(Tree<T> that) {
if (this == that)
return true;
if (that == null)
return false;
//check the equality of the current node's data for both this and that.
if (this.data == that.data || (this.data != null && this.data.equals(that.data))) {
//check the left hand side of the current node for both this and that.
if ((this.left == null && that.left == null
|| this.left != null && this.left.isIdentical(that.left))
//check the right hand side of the current node for both this and that.
&& (this.right == null && that.right == null
|| this.right != null && this.right.isIdentical(that.right))) {
return true;
}
}
return false;
}
You could stay with a recursion and make isIdentical(myTree, Othertree) private. Then wrap it inside a method IsIdentical(otherTree) that calls the method with two arguments suppling this (refrence to the current object) as the first parameter.

How to handle null check when searching for a node in Binary Search Tree

I have the following code to search for a node in a BST:
private Node<AnyType> searchAndGetNode(AnyType value) {
Node<AnyType> currentNode = root;
while(currentNode != null && currentNode.getData() != null) {
if (value.compareTo(currentNode.getData()) == 0) {
return currentNode;
} else if (value.compareTo(currentNode.getData()) < 0) {
currentNode = currentNode.getLeft();
} else {
currentNode = currentNode.getRight();
}
}
return null;
}
I am aware of Optional.ofNullable() to get an Optional object and then use isPresent() to avoid null-check. But I could not think of any neat way to avoid null check comparison in the while loop in the above method. I am using Java 8. Please suggest.
You should remove the && currentNode.getData() != null part of the condition as it doesn't make sense for there to be null values in a binary tree (your cannot call compareTo on null, so where would you insert it into the tree?). Apart from that, there is nothing wrong with the null check you have.
However, for performance, you should not call compareTo twice for each value, but call it once and examine the result:
int cmp = value.compareTo(currentNode.getData());
if (cmp == 0) {
return currentNode;
} else if (cmp < 0) {
currentNode = currentNode.getLeft();
} else { // cmp > 0
currentNode = currentNode.getRight();
}
But I could not think of any neat way to avoid null check comparison
in the while loop
There's nothing wrong with !=null.
But you could use an interface with Leafs and Nodes instead (and make use of default method with Java 8).
interface Tree<T> {
boolean isEmpty();
default T getData() {
throw new UnsupportedOperationException();
}
default Tree<T> getLeft() {
throw new UnsupportedOperationException();
}
default Tree<T> getRight() {
throw new UnsupportedOperationException();
}
}
class Leaf<T> implements Tree<T> {
#Override
public boolean isEmpty() {
return true;
}
}
class Node<T> implements Tree<T> {
public Node(Tree<T> left, Tree<T> right, T data) {...}
//implement getLeft, getRight etc.
#Override
public boolean isEmpty() {
return false;
}
}
Then there is no more need for null checks in your code (following #Boann on this point, where would you store a null reference in your BST?):
class BST<T extends Comparable<? super T>> {
...
private Tree<T> searchAndGetNode(T value) {
Tree<T> currentNode = root;
while(!currentNode.isEmpty()) {
int cmp = value.compareTo(currentNode.getData());
if (cmp == 0) {
return currentNode;
} else if (cmp < 0) {
currentNode = currentNode.getLeft();
} else {
currentNode = currentNode.getRight();
}
}
return currentNode; //it will be a Leaf at this point
}
}
Then you could just call isEmpty() to check whether a Node or a Leaf has been returned from the searchAndGetNode method.
Some might argue that isEmpty() could also be implemented in the Tree interface.
You have to check it somewhere, if not in the while condition than in the getLeft() and getRight() (either when you call it or inside it). The option you chose is better IMHO because you check only once while the other alternatives require multiple checks.
You can't avoid the null check. You must have some condition to determine when you finish searching the tree without finding the requested Node. Whether this check compares some reference to null or asks if some Optional is empty makes no difference.
I think your code works as it should. When you enter right/left child that does not exist or has null value, you will simply quit your while loop. You need an end condition to your loop, and null is the place.
I would only advise to replace
currentNode.getData() != null
with a method for this node, like currentNode.hasData(). This will hide your logic and will be more readable:)
private Node<AnyType> searchAndGetNode(AnyType value) {
Node<AnyType> currentNode = root;
while(currentNode != null && currentNode.getData() != null) {
int comparedValue = value.compareTo(currentNode.getData());//compare once. Because this is a int
if (comparedValue == 0) {
return currentNode;
} else if (comparedValue < 0) {
currentNode = currentNode.getLeft();
} else {
currentNode = currentNode.getRight();
}
}
return null;
}

Recursive compare two binary search trees

I need to compare two binary search trees and see if they are equal or not.
I developed following code that uses recursion.
private boolean compareTrees(BinaryTreeNode n1, BinaryTreeNode n2)
{
if(n1.getNodeData() != n2.getNodeData())
return false;
else
{
if(n1.left != null && n2.left != null)
compareTrees(n1.left, n2.left);
if(n1.right != null && n2.right != null)
compareTrees(n1.right, n2.right);
}
return true;
}
The problem is that if two nodes are not equal, the method will return false but because I use recursion, the return value will be overridden to true no matter what. I have been stuck with this problem for all day and nothing worked for me. I searched online but I didn't find anything relevant to my code.
Is there any way to break from all nested methods and return value to the first method?
You need to return the result of the subtree comparison:
boolean b1, b2;
if(n1.left != null && n2.left != null)
b1 = compareTrees(n1.left, n2.left);
if(n1.right != null && n2.right != null)
b2 = compareTrees(n1.right, n2.right);
return b1 && b2;
But why not just deal with nulls before-hand?
private boolean compareTrees(BinaryTreeNode n1, BinaryTreeNode n2)
{
if (n1 == null || n2 == null)
return n1 == n2; // i.e. both null
if (n1.getNodeData() != n2.getNodeData())
return false;
return compareTrees(n1.left, n2.left) && compareTrees(n1.right, n2.right);
}
I would do it changing the order:
private boolean compareTrees(BinaryTreeNode n1, BinaryTreeNode n2)
{
boolean equalLeft = false;
boolean equalRight = false;
if(n1.getNodeData() == n2.getNodeData())
{
if(n1.left != null && n2.left != null){
equalLeft = compareTrees(n1.left, n2.left);
} else{
equalLeft = true;
}
if(n1.right != null && n2.right != null){
equalRight = compareTrees(n1.right, n2.right);
} else{
equalRight = true;
}
return equalLeft && equalRight;
} else{
return false;
}
}
Try to face the problem avoiding null values and using equals() method instead of == comparison for your nodes. I shoud do it this way:
private boolean compareTrees(BinaryTreeNode n1, BinaryTreeNode n2){
//avoid nulls :TDD
if (n1==null && n1==n2)
return true;
if ((n1==null && n2!=null) || (n2==null && n1!=null))
return false;
//ensure logic without nulls, comparing with equals() method
boolean areEquals = n1.getNodeData().equals(n2.getNodeData());
//compare left
areEquals = areEquals && compareTrees(n1.left, n2.left);
//if still equals, compare right
if(areEquals) areEquals = areEquals && compareTrees(n1.right, n2.right);
return areEquals;
}
Effectively, your code could reduce to:
private boolean compareTrees(BinaryTreeNode n1, BinaryTreeNode n2)
{
if(n1==null || n2==null) return n1==n2;
return (n1.getNodeData()==n2.getNodeDate()) && compareTrees(n1.left, n2.left) && compareTrees(n1.right, n2.right)
}
I will tell you couple of problems your code has.
Termination criteria when root is null (it will always happen in the end).
Return statements in recursive calls. You are always returning the true in the end.
PS: If you add NULL checks (explained in 1), you need not to add null checks in the subsequent recursive calls. Now the second half of your code will look like:
return compareTrees(n1.left, n2.left) && compareTrees(n1.right, n2.right);

Recursively searching binary tree issue

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;
}

Categories