Equals and hashcode implementation for BST
This question is kind of a follow-up to BST's hashCode implementation . My question was poorly thought out and so I got the answer that I don't know how to use it.
I need to implement equals
for BST: so iff two BSTs are equal in structure and content then equals
returns true. As such, I suppose I also need to implement the function hashCode
. I got the answer for the hashCode function so that the trees are the same 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 how do you implement the equals function? Will iff's next job be equal to trees both in structure and in content?
@Override
public boolean equals(Node otherRoot){
return root.hashCode() == otherRoot.hashCode();
}
Are there circumstances where I might mistakenly trust?
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 my equals
will avoid false positives?
source to share
Will iff's next job be equal trees both in structure and in content?
root.hashCode() == otherRoot.hashCode()
No, it won't work because hash code equality is a one-way street: when objects are equal, hash codes must be equal. However, when the objects are not equal, the hash codes may or may not be equal. This makes sense if you apply the pigmentation principle: the number of possible hash codes is about 4B, and the number of possible BSTs is almost infinite.
You can plot the comparison the same way you plotted the hash code, i.e. recursively:
- Check if the values in 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 does not, return
false
- Check if both nodes have the correct subtree. If one of them has a right subtree and the other does not, return
false
- Apply
equals
recursively to left subtrees. If resultfalse
, returnfalse
- Apply
equals
recursively to the right subtrees. If resultfalse
, returnfalse
- Return
true
source to share
Not sure what objects there are, but your latest hashCode () example should 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 see an overflowing h if the tree is deep enough, with all h * 31.
The contract for hashCode does not guarantee equality, so you will probably need to call everything equal down the tree to make sure everything balances out.
source to share
I haven't tested this for sure, but here's to get started
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);
}
}
source to share
The second implementation hashCode
looks good to me, but you can never avoid collisions with hash codes when the number of possible objects is greater than the range int
- here and here, so you shouldn't use a hash code in equals
.
What you should do is something like this (assuming the name of the class 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;
}
source to share