This question is sort of a follow up to Implementing hashCode for a BST. My question was poorly thought through and so I got an answer that I am not sure how to use.
I need to implement equals for a BST: so that iff two BSTs are equal in structure and content, then equals returns true. As such, I imagine I also need to implement the hashCode function. I got the answer for the hashCode function such that the trees are equal in structure and content.
#Override
puclic int hashCode(){
int h = Objects.hashCode(data);//data is int
int child=0;
if(null != left)
child =left.hashCode();
if(null != right)
child+= right.hashCode();
if(0<child) h= h*31+child;
return h;
}
But then how do I implement the equals function? Will the following work iff the trees are equal in both structure and content?
#Override
public boolean equals(Node otherRoot){
return root.hashCode() == otherRoot.hashCode();
}
Might there be circumstances where I can false positives?
Or should my hashCode be
#Override
public int hashCode(){
int h = contents.hashCode();
h = h * 31 + Objects.hashCode(leftChild);
h = h * 31 + Objects.hashCode(rightChild);
return h;
}
and in this latter case, would my equals avoid false positives?
Will the following work iff the trees are equal in both structure and content? root.hashCode() == otherRoot.hashCode()
No, it would not work, because hash code equality is a one-way street: when objects are equal, hash codes must be equal. However, when objects are not equal, hash codes may or may not be equal. This makes sense once you apply a pigeonhole principle: the number of possible hash codes is about 4B, while the number of possible BSTs is virtually infinite.
You can build a comparison in the same way that you built the hash code - i.e. recursively:
Check if the values at the nodes being compared are equal to each other. If the values are different, return false
Check if both nodes have a left subtree. If one of them has a left subtree and the other one does not, return false
Check if both nodes have a right subtree. If one of them has a right subtree and the other one does not, return false
Apply equals recursively to left subtrees. If the result is false, return false
Apply equals recursively to right subtrees. If the result is false, return false
Return true
Not sure what Objects is, but your last hashCode() example needs to handle null, I would think something like:
#Override
public int hashCode() {
int h = contents.hashCode();
if (leftChild != null) h = h* 31 + leftChild.hashCode();
if (rightChild != null) h = h * 31 + rightChild.hashCode();
return h;
}
I can see overflowing h if the tree is deep enough, with all the h * 31.
The contract for hashCode does not guarantee equality, so you probably need to call equals all the way down the tree to make sure everything balances out.
I haven't tested this exactly but here's somewhere to start
public boolean equals(Object o) {
// exact same object
if(this === o) {
return true;
}
if(!o instanceof Node) {
return false
}
Node otherTree = (Node) o;
boolean selfHasLeft = this.left == null,
selfHasRight = this.right == null,
otherHasLeft = otherTree.left == null,
otherHasRight = otherTree.right == null;
// this tree must have the same children as the other tree
if(selfHasLeft != otherHasLeft || selfHasRight != otherHasRight) {
return false;
}
// must have same value
if(this.value != other.value) {
return false;
}
// if they have no children then now they should be the same tree
// otherwise, check that their children are the same
if(!selfHasLeft && !selfHasRight) {
return true;
} else if(selfHasLeft && !selfHasRight) {
return this.left.equals(otherTree.left);
} else if(selfHasRight && !selfHasLeft) {
return this.right.equals(otherTree.right);
} else {
return this.left.equals(otherTree.left) && this.right.equals(otherTree.right);
}
}
Your second hashCode implementation looks good to me, but you can never avoid hashcode collisions when the number of possible objects are greater than the range of an int - which is the case here so you should not use the hashcode in equals.
What you should do is something like this (assuming the class name is BST):
public boolean equals(Object other) {
if(this == other) {
return true;
}
if(!(other instanceof BST)) {
// If other is null we will end up here
return false;
}
BST bst = (BST) other;
// Check equality of the left child
if(left != null) {
if(!left.equals(other.left)) {
// Left childs aren't equal
return false;
}
} else if (other.left != null) {
// this.left is null but other.left isn't
return false;
}
// Check equality of the right child
if(right != null) {
if(!right.equals(other.right)) {
// Right childs aren't equal
return false;
}
} else if (other.right != null) {
// this.right is null but other.right isn't
return false;
}
// Both left and right childs are equal
return true;
}
Related
This is what I have to do. The Binary Search Tree ADT is extended to include a bool ean method si m i l ar Trees that receives references to two binary trees and determines whether the shapes of the trees are the same. (The nodes do not have to contain the same values, but each node must have the same number of children.) I have code to show what I have.
public static <T> boolean similarTrees(BSTNode<T> a, BSTNode<T> b) {
// check for reference equality and nulls
if (a == b) return true; // note this picks up case of two nulls
if (a == null) return false;
if (b == null) return false;
// check for data inequality
if (a.data != b.data) {
if ((a.data == null) || (b.data == null)) return false;
if (!(a.data.equals(b.data))) return false;
}
// recursively check branches
if (!similarTrees(a.left, b.left)) return false;
if (!similarTrees(a.right, b.right)) return false;
// we've eliminated all possibilities for non-equality, so trees must be equal
return true;
}
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.
What I need is: Verify if an object exist in a List comparing some attributes.
I'm in a trouble here with Collections and Comparator. I'm trying to do the verify with this Binary Search:
Collections.binarySearch(listFuncionarioObs2, formFuncionarioObsIns, formFuncionarioObsIns.objectComparator);//Binary search of an object in a List of this Object.
With this comparator:
public int compare(FuncionarioObs func, FuncionarioObs funcToCompare) {
int testCodigo = -1;
if(null != func2.getCodigo()){
testCodigo = func.getCodigo().compareTo(funcToCompare.getCodigo());
}
int testData = func.getData().compareTo(funcToCompare.getData());
int testEvento = func.getEvento().compareTo(funcToCompare.getEvento());
int testAndamento = func.getAndamento().compareTo(funcToCompare.getAndamento());
if(testCodigo == 0 && testData == 0 && testEvento == 0 && testAndamento == 0){
return 0;
}else if(testData == 0 && testEvento == 0 && testAndamento == 0) {
return 0;
}
return -1;
}
But I'm a little bit lost, this is not working and I don't know the best way to do this. Someone can turn on a light for me?
Best regards,
Edited.
I'm sorting the List before the Binary Search with this code:
List<FuncionarioObs> listFuncionarioObsBD = funcionarioObsDAO.getFuncionarioObsById(sigla);
Collections.sort(listFuncionarioObsBD);
The comparator to the sort is:
#Override
public int compareTo(FuncionarioObs func) {
if(this.getCodigo() > func.getCodigo()){
return 1;
}else if(this.getCodigo() == func.getCodigo() ) {
return 0;
}else{
return -1;
}
}
CompareTo
Your compare wont work correctly. Right now it is only comparing the references of the objects. You will have to change this to compare the objects values:
#Override public int compareTo(Account aThat) {
final int BEFORE = -1;
final int EQUAL = 0;
final int AFTER = 1;
//this optimization is usually worthwhile, and can
//always be added
if (this == aThat) return EQUAL;
//primitive numbers follow this form
if (this.fAccountNumber < aThat.fAccountNumber) return BEFORE;
if (this.fAccountNumber > aThat.fAccountNumber) return AFTER;
//booleans follow this form
if (!this.fIsNewAccount && aThat.fIsNewAccount) return BEFORE;
if (this.fIsNewAccount && !aThat.fIsNewAccount) return AFTER;
.
.
.
//all comparisons have yielded equality
//verify that compareTo is consistent with equals (optional)
assert this.equals(aThat) : "compareTo inconsistent with equals.";
return EQUAL;
}
from here
Finding the object
Now comes the next part. As CrtlAltDelete has hinted it dependends of whether your list is sorted or not.
If its sorted ascending: iterate through the objects till you either find one which compareTo returns a Zero (== success) or a One ( == fail).
For an unsorted list you will have to iterate through all objects in search for one that returns a Zero.
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;
}
}
I have an array of a custom type that I want to sort by one of its String attributes. For some reason, the following code is producing wrong results. Could you point out where I might have made a mistake?
class PatientLNComparator implements Comparator<Patient>{
#Override
public int compare(Patient p1, Patient p2) {
String p1_LN = (p1 == null) ? null : p1.last_name;
String p2_LN = (p2 == null) ? null : p2.last_name;
if(p2_LN == null)
return -1;
else if(p1_LN == null)
return +1;
else if(p1_LN.equals(p2_LN))
return 0;
else if(p1_LN.compareTo(p2_LN) > 0)
return -1;
else
return +1;
}
}
One problem to start with - your comparator is inconsistent if you give it two patients with null names, or two null patient references. In particular:
Patient p1 = null;
Patient p2 = null;
int x = comparator.compare(p1, p2);
int y = comparator.compare(p2, p1);
The signs of x and y ought to be different - but they'll both be -1.
After that, it depends on how you want to compare the names. I would usually use
return p1_LN.compareTo(p2_LN);
if you want to sort in ascending order. Note that to sort in descending order you shouldn't just return -p1_LN.compareTo(p2_LN), as if the comparison returns the Integer.MIN_VALUE, the negation won't work. Instead you'd want to return p2_LN.compareTo(p1_LN);.
Note that if you're using this scheme, you don't need to call p1_LN.equals(p2_LN) either - that will be handled by the compareTo call.
You want patient to be ordered by alphabetical by last name, null patients and null last names up front?
class PatientLNComparator implements Comparator<Patient>{
#Override
public int compare(Patient p1, Patient p2) {
String p1_LN = (p1 == null) ? null : p1.last_name;
String p2_LN = (p2 == null) ? null : p2.last_name;
if (p1_LN == null && p2_LN == null)
return 0;
else if (p2_LN == null)
return -1;
else if(p1_LN == null)
return +1;
else
return p1_LN.compareTo(p2_LN);
}
}
To be stable, it really should order by some other fields, like first name, when last names are equal.
I'm assuming you want natural string ordering for this.
First of all, as it is, your compareTo branch is giving inversed results. Don't know if that's what you intended or not (as in you're saying p1 is greater than p2 when the p1's string is lower than p2's).
Furthermore, you can ditch the .equals branch of the if. The compareTo already handles this case.
Therefore a simple
if(p2_LN == null && p1_LN == null)
return 0;
else if(p1_LN == null)
return +1;
else if(p2_LN == null)
return -1;
else return p1_LN.compareTo(p2_LN)
would suffice.
I would use Guava's Ordering class for this:
class Patient {
// ...
public static final Function<Patient, String> GET_LAST_NAME =
new Function<Patient, String>() {
public String apply(Patient from) {
if (from == null) return null;
return from.last_name;
}
};
public static final Comparator<Patient> BY_LAST_NAME =
Ordering.natural()
.onResultOf(GET_LAST_NAME)
.nullsFirst();
}
This will resolve the issue with inconsistent comparison of nulls. It also makes it easy to add a secondary order (e.g. first name):
public static final Comparator<Patient> BY_LAST_NAME =
Ordering.natural()
.onResultOf(GET_LAST_NAME)
.compound(Ordering.natural().onResultOf(GET_FIRST_NAME))
.nullsFirst();