Does anyone know the best way to approach this problem?
I'm getting the following error, which I assume means I need a different approach to compare the data element of the node.
java: bad operand types for binary operator '<'
first type: V
second type: V
Code:
class Node<V> {
Node<V> left;
Node<V> right;
V data;
public Node(V d) {
left = null;
right = null;
data = d;
}
public void Insert(V d) {
if (data != null) {
if (d < data) {
if (left == null) {
left = Node(d);
} else {
left.Insert(d);
}
}
}
}
}
As already suggested in the comments by @Dan W, the generic type V
in the Node
class should define an upper bound to Comparable
in order to restrict the possible types in place of V
to only the ones that can be compared (ordered).
In Java, the operators <
, >
, <=
, >=
can be used only for numeric primitive types, such as int
, float
, double
, and so on. Instead, to compare reference types, their class needs to implement the Comparable
interface to define a natural ordering among their elements.
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
Most Java classes like Integer
, Float
, Double
and many others already implement the Comparable
interface, while for your own classes you need to provide the comparison logic within the compareTo
method. Here is also a great article from Bealdung with a guide on how to implement the Comparable
interface.
In your case, a generic version of your class Node
can be re-written in the following way:
class Node<V extends Comparable<? super V>> {
Node<V> left;
Node<V> right;
V data;
public Node(V d) {
left = null;
right = null;
data = d;
}
public void Insert(V d) {
if (data != null) {
if (d.compareTo(data) < 0) {
if (left == null) {
left = new Node<>(d);
} else {
left.Insert(d);
}
}
}
}
}
In the previous snippet, the type parameter for Comparable
is written with a lower bounded wildcard (Comparable<? super V>
) instead of just the generic parameter V
(Comparable<V>
), so that classes that do not implement directly the Comparable
interface can be accepted as well when their supertypes actually do. This is the case, for example, for the LocalDate
class, which does not implement Comparable
directly, but its supertype ChronoLocalDate
actually does. Like so, also LocalDate
instances can be accepted and confronted.
A particular thank you to @Holger for pointing this out in the comments.