BinaryTree Generic CompareTo - java

Ok, so I'm I'm working on a school project where we implement a Binary TreeMap and given a basic template to fill out. I'll try to not dump all of the code but here's where I'm hitting a wall. I need to be able to compare keys so insert new elements, properly search and whatnot. But I keep getting a Bad Operand error.
private class Element {
K key;
V value;
public Element(K key, V value) {
this.key = key;
this.value = value;
}
public int compareTo(Element that) {
if (key < that.key) //Error Here
return -1;
else if(key > that.key) //And here
return 1;
else
return 0;
}
}
Now this class is a subclass of the TreeMap class. Again I won't dump the whole code, but the header is like so:
public class TreeMap<K extends Comparable<K>,V> implements MyMap<K,V>
Now everywhere I look seems to point that having K extends Comparable<K> should allow these to be comparable, but they're not. This header was provided by the teacher, so I don't think it needs to be altered. Am I just overlooking or forgetting something?

You can't compare Comparable objects using < and >. Those are only for numeric values. Instead, you can use something like this:
public int compareTo(Element that) {
final int comp = key.compareTo(that.key);
if (comp < 0)
return -1;
else if(comp > 0)
return 1;
else
return 0;
}
Or, better, just return the result of calling compareTo():
public int compareTo(Element that) {
return key.compareTo(that.key);
}

Related

Casting with Comparable

I'm trying to find the minimum value of a node within a tree, and in order to detect whether something has smaller value, I'm using the compareTo() function as seen below:
#SuppressWarnings("unchecked")
public static Object min(TreeNode t)
{
if(t == null) {
return null;
}
Comparable<TreeNode> min = (Comparable<TreeNode>) t;
if(t.getLeft() != null) {
Comparable<TreeNode> leftMin = (Comparable<TreeNode>) min(t.getLeft());
if( ((Comparable<TreeNode>)leftMin).compareTo( (Comparable<TreeNode>)min) < 0) {
min = leftMin;
}
}
if(t.getRight() != null) {
Comparable<TreeNode> rightMin = (Comparable<TreeNode>) min(t.getRight());
if( ((Comparable<TreeNode>)rightMin).compareTo( (Comparable<TreeNode>)min) < 0) {
min = rightMin;
}
}
return min;
}
However, I'm receiving the following error:
error: incompatible types: Comparable<TreeNode> cannot be converted to TreeNode
at the if statement.
I was told that the Object must be cast to Comparable in order to call compareTo()
And I have tried looking at this similiar question, but I don't have access to change the TreeNode Class
TreeNode Class:
public class TreeNode
{
private Object value;
private TreeNode left, right;
public TreeNode(Object initValue)
{
value = initValue;
left = null;
right = null;
}
/*methods*/
}
And I have also tried: if(leftMin.compareTo(min) < 0) however that yields the same error.
Do you know how to properly cast and convert the following classes?
As suggested by others, you can use the comparable interface, which will require you to implement the compareTo method.
The compare to implementation details can be found in the java se docs:
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object.
So we can change your class to something like what is shown below (Note: I recommend converting value to an int or any other primitive type):
class TreeNode implements Comparable<TreeNode> {
// recommend to convert value to int or any other primitive type
private Object value;
private TreeNode left, right;
public TreeNode(Object initValue) {
value = initValue;
left = null;
right = null;
}
// if value is int, just use ==, < and >
// i.e. this.value == o.value, this.value < o.value and so on ...
#Override
public int compareTo(TreeNode o) {
if (this.value.equals(o.value)) return 0;
else if (this.value.hashCode() < o.value.hashCode()) return -1;
else return 1;
}
/*methods*/
}
Then you don't really need to do the casting in the min method. (Note: The implementation below is not actually correct - won't give you the min. It's just shown as to how the implementation would change after implementing the comparable interface).
// This method is not actually correct (i.e. won't actually find the min),
// but showing how it would change after using the comparable interface
// on the tree node class.
public TreeNode min(TreeNode t) {
if(t == null) {
return null;
}
TreeNode min = t;
if(t.getLeft() != null) {
TreeNode leftMin = min.getLeft();
if(leftMin.compareTo(min) < 0) {
min = leftMin;
}
}
if(t.getRight() != null) {
TreeNode rightMin = min.getRight();
if( rightMin.compareTo(min) < 0) {
min = rightMin;
}
}
return min;
}
The class TreeNode must implement the Comparable interface:
public class TreeNode implements Comparable<TreeNode> {
...
#Override
public int compareTo(TreeNode other) {
... // maybe compare 'initValue' here
}
}
also not sure if it is so good to cast TreeNode to Comparable, I would prefer to work
without casting at all (e.g. public static TreeNode min(TreeNode t))
Edit: probably it was meant to cast initValue to Comparable so it can be compared - not very (type-) safe having it declared as Object in that case.
Edit after question changed. Since TreeNode cannot be changed, I think you must clearly split nodes and values, probably something like below (must be completed):
public static TreeNode min(TreeNode node) {
...
TreeNode minNode = node;
Comparable<?> minValue = (Comparable<?>) minNode.getValue(); // guessed method name
if (node.getLeft() != null) {
TreeNode leftMin = min(t.getLeft());
Comparable<?> leftValue = (Comparable<?>) leftMin.getValue();
if (leftValue.compareTo(minValue) < 0) {
minNode = leftNode;
minValue = leftValue;
}
...
This requires that instances in Value implement Comparable.

How do I access the child's fields of an object inside a user defined treeset?

public class Dog extends Animal implements Comparable<Animal> {
private String name;
private String breed;
private boolean isPottyTrained;
public class Frog extends Animal implements Comparable<Animal> {
private String color;
private double maxJump;
private int bugsEatenPerDay;
public class Animal {
private double weight;
private double height;
private double length;
I've created a TreeSet of type Animal. I have 2 children of Animal (Dog and Frog). My goal is to set the natural order of Dog class in alphabetical order by its name and Frog class to be ordered by its color (in alphabetical order).
public int compareTo(Animal o) {
if (o.getClass().equals(Dog.class)) {
int temp = this.name.compareToIgnoreCase(o.getClass().getName());
if (temp == 0) {
return 0;
} else if (temp > 0) {
return 1;
} else {
return -1;
}
}
return 0;
} // I am not even sure what is producing
This is the code I've tried in the Dog class, but it did not yield any result.
Ideally, I want the code to be something like
if (this.name > o.getName()) {
...
} //pseudocode
But I know it's not possible for the parent to access the fields of the children. Is there a way to work around this?
If by 'child' you mean subclass, you should be able to access the subclass methods by casting, like so:
((Dog) o).getName()
This will only work if you cast the less specific class to a more specific class that it implements, otherwise it will throw a ClassCastException.
The complete solution, then, would look like this:
public int compareTo(Animal o) {
if (o instanceof Dog)
return this.name.compareToIgnoreCase(((Dog) o).getName());
return 0;
}
This solution, however, assumes that everything that is not a dog is equal, so you'll likely want to implement logic for the other animals as well.
You mention that you don't know what the compare function is producing; it's producing a number that means one of the following:
The object is 'less than' the parameter value (<= -1)
The object is 'equal to' the parameter value (0)
The object is 'greater than' the parameter value (>= 1)
This can be used, for instance, to sort a list according to rules you define.
public int compareTo(Animal o) {
if (o instanceof Frog) {
int compare = this.name.compareToIgnoreCase(((Frog) o).getColor());
if (compare > 0) {
return 1;
} else if (compare < 1) {
return -1;
} else {
return 0;
}
} else if (o instanceof Dog) {
int compare = this.name.compareToIgnoreCase(((Dog) o).getName());
if (compare > 0) {
return 1;
} else if (compare < 1) {
return -1;
} else {
return 0;
}
}
return 0;
}// end compareTo
This is inside Dog class. Same principle apply to the Frog class

HashMap.containsKey(key) failing to find key, with custom class used as key type

TL;DR: I made a hashmap object with my own "Pair" class objects to be used as Keys. When I use hashmap.containsKey(Pair), it fails to find the key.
I have a class called Pair, code shown below. It's supposed to be a container for two objects. The first object can be of any type, whereas the second object must be an integer. This isn't great design but I coded it this way so I could reuse the class for other purposes within my program.
import java.util.ArrayList;
public class Pair<L> {
private L left;
private int right;
public Pair(L left, int right) {
this.left = left;
this.right = right;
}
public L getLeft() { return left; }
public int getRight() { return right; }
public void ToString() {
System.out.println(left + "," + right);
}
public boolean equals(Pair p) {
return (this.getLeft().equals(p.getLeft()) && this.getRight() == p.getRight());
}
public ArrayList<Pair> neighbors(int rowLimit, int ColumnLimit) {
ArrayList<Pair> neighbors = new ArrayList<Pair>();
Pair neighborL;
Pair neighborR;
Pair neighborU;
Pair neighborD;
if (((int)this.left-1 >= 0)) {
neighborU = new Pair((int)this.left-1, this.right);
// neighborU.ToString();
neighbors.add(neighborU);
}
if ((int)this.left+1 < rowLimit) {
neighborD = new Pair((int)this.left+1, this.right);
// neighborD.ToString();
neighbors.add(neighborD);
}
if ((int)this.right-1 >= 0) {
neighborL = new Pair((int)this.left, this.right-1);
// neighborL.ToString();
neighbors.add(neighborL);
}
if ((int)this.right+1 < ColumnLimit) {
neighborR = new Pair((int)this.left, this.right+1);
// neighborR.ToString();
neighbors.add(neighborR);
}
return neighbors;
}
}
I'm storing Pairs as keys in a hashmap like this:
Map<Pair, Integer> costSoFar = new HashMap<Pair, Integer>();
costSoFar.put(sLocale, 0);
When I run the line below, which is to say, if the key is not in the hashmap:
if (!costSoFar.containsKey(next))
It evaluates to true, even when I know the key is in there, as I've checked through debugging.
If anyone can help clear up why the hashmap isn't recognizing the keys it'd be much appreciated. Perhaps my equals method isn't up to scratch?
Why are you using Generics if L seems to be int too?
Replace your equals:
public boolean equals(Object o) {
if (o instanceof Pair){
Pair p = (Pair)o;
return (this.getLeft().equals(p.getLeft()) && this.getRight() == p.getRight());
}
return false;
}
And implement int hashCode():
public int hashCode() {
return this.getLeft() * 31 + this.getRight();
}
Method containsKey(Object) in java.util.HashMap use the java.util.HashMap.getEntry(Object) which call hashCode() to obtain the hashCode for the Key and use it to retrive the object. You need to override java.lang.Object.hashCode() to make your code properly work.

Put method of a TreeMap implementation

I'm working on an implementation of TreeMap(called MyTreeMap) and I'm having a lot of trouble with the put method. I was hoping someone could look at my code and point me in the right direction as to where things start to go wrong.
public class MyTreeMap<K extends Comparable<? super K>,V> extends AbstractMap<K,V> {
K key;
V value;
int height;
MyTreeMap<K,V> left,right;
int size;
public V put(K key, V value) {
int compareValue = this.key.compareTo(key);
if(!this.containsKey(key)) {
if(this.key == null) {
this.key = key;
this.value = value;
}
if(this.isLeaf() || this.isEmpty()) {
if(this.key.compareTo(key) > 0)
this.left = new MyTreeMap<K,V>(key,value,null,null);
else
this.right = new MyTreeMap<K,V>(key,value,null,null);
if(left.height > right.height + 1 || right.height > left.height + 1)
restructure(this);
this.size++;
setHeight();
return null;
}
else {
if(compareValue > 0)
return this.left.put(key, value);
else
return this.right.put(key, value);
}
}
else {
if(compareValue == 0) {
V temp = this.value;
this.value = value;
return temp;
}
else if(compareValue < 0)
return this.right.put(key, value);
else
return this.left.put(key, value);
}
}
I think your logic is a bit inside-out, and as a result is a lot more complicated than it needs to be: the top level if should probably be looking at the compareValue, not doing the containsKey check.
Logic should be:
if compareValue==0 then this means you have found the right key, so just update the value and return
otherwise check the left or right branch as appropriate (depending on sign of compareValue):
if the branch is null, then turn it into a new TreeMap branch containing your key and value (you are now done)
otherwise (branch is not null), call put recursively on this branch. If you like you can do rebalancing logic after this call.
P.S. I suggest not allowing null keys in a TreeMap, it will make your life simpler, and will avoid the need to do null checks on keys

How do I correctly implement Comparable for List in this instance?

What I want to do is use the compareTo() method to compare removedItemFromList1 and removedItemFromList2, then insert whichever value is smaller into the modifiedList3 and put the larger of the two removedFromList 1 or 2 back into its original list. If I had hair long enough to pull, it would have been pulled out by now...Am I not casting correctly? How do I correctly go about using the compareTo() method to accomplish this?
public class List<Integer> implements Comparable
{
private ListNode<Integer> firstNode;
private ListNode<Integer> lastNode;
public void insertAtBack (Integer insertItem)
{
if ( isEmpty())
firstNode = lastNode = new ListNode<Integer>(insertItem);
else
lastNode = lastNode.nextBasket = new ListNode<Integer>( insertItem );
}
public Integer removeFromBack()
{
Integer removedItem = (Integer) lastNode.topBucketInBasket;
if ( firstNode == lastNode)
firstNode = lastNode = null;
else
{
ListNode<Integer> current = firstNode;
while ( current.nextBasket != lastNode)
current = current.nextBasket;
lastNode = current;
current.nextBasket = null;
}
return removedItem;
}
public boolean isEmpty()
{
return firstNode == null;
}
public List<Integer> merge(List<Integer> list1, List<Integer> list2)
{
List<Integer> modifiedList3 = new List<Integer>();
Integer removedItemFromList1 = (Integer) list1.removeFromBack();
Integer removedItemFromList2 = (Integer) list2.removeFromBack();
((Comparable) removedItemFromList1).compareTo( removedItemFromList2);
int comparison = compareTo(removedItemFromList2);
if ( comparison == 1)
modifiedList3.insertAtBack(removedItemFromList2);
list1.insertAtBack(removedItemFromList1);
if ( comparison == -1)
modifiedList3.insertAtBack(removedItemFromList1);
list2.insertAtBack(removedItemFromList2);
return modifiedList3;
}
#Override
public int compareTo(Integer itemToCompare)
{
final int BEFORE = -1;
final int AFTER = 1;
if (this.removedItemFromList1 < list2.removedItemFromList2) return BEFORE;
if (this.removedItemFromList1 > list2.removedItemFromList2) return AFTER;
}
}
You should implement the generic version Comparable<Integer> instead of the raw version Comparable.
Also, in the following
public class List<Integer> implements Comparable
That Integer is not the same as java.lang.Integer. Actually, it's something called formal type parameter in that context.
You probably want to change it to
//List is kind of ambiguous with java.util.List
public class MyList<E> implements Comparable<Integer> {
or may be something else instead of MyList.
If you implement Comparable it should be
#Override
public int compareTo(Object itemToCompare) {
and if Comparable<Integer> (which is the one you are after, I guess), it should be
#Override
public int compareTo(Integer itemToCompare)
The difference is the parameter types - Object and Integer.
It's kind of messy and not so clear what you are trying to acheive.
But the point that your List class implements Comparable indicates that you want to compare an instance of List with another instance. If that's the case then it should like something like this -
public class MyList<E> implements Comparable<MyList> {
#Override
public int compareTo(MyList other) {
//compare and return result
}
But the fact that the parameter type is Integer suggest that what you are actually trying to compare are Integers, in which case Integer is already Comparable.
((Comparable) removedItemFromList1).compareTo( removedItemFromList2);
You don't need to do all that
removedItemFromList1.compareTo(removedItemFromList2);
is enough. And if that's all you need then you don't need implement Comparable at all, so can remove that compareTo method also.
The Comparable interface goes this way
public interface Comparable<T> {
public int compareTo(T t){
}
}
You should use the Type Parameter. Comparable is Type Parametrized.
So try it this way...
public class mList<Integer> implements Comparable<Integer>{
......
public int compareTo(Integer itemToCompare){
.....
}
}

Categories

Resources