Implementing Binary Tree in Java with Generic Comparable<T> data? - java

Q: In my implementation of a binary tree below, why does the compiler choke at
if (data.compareTo(this.data) <= 0),
producing
Error: incompatible types: java.lang.Comparable<T> cannot be converted to T?
Both data and this.data are of type Comparable<T> and should be able to use or be an argument to the compareTo() method...right? Well, clearly not. But I really don't understand why. Generics are still baffling me.
public class MyBinaryTreeNodeG<T>{
Comparable<T> data;
MyBinaryTreeNodeG<T> parent;
MyBinaryTreeNodeG<T> left;
MyBinaryTreeNodeG<T> right;
public MyBinaryTreeNodeG(Comparable<T> data){
this.data = data;
}
public MyBinaryTreeNodeG<T> addChild(Comparable<T> data){
if (data.compareTo(this.data) <= 0) { //this is the line on which the compiler chockes
//check if left tree node is null. If so, add. Otherwise, recurse.
} else {
//same for the right tree node
return null;
}
The following is a clip from a more standard implementation of a binary tree. This compiles fine. But I still fail to see why this is a "better" (according to compiler) implementation than mine above.
public class MyBinaryTreeNodeG<T extends Comparable<T>>{
T data;
MyBinaryTreeNodeG<T> parent;
MyBinaryTreeNodeG<T> left;
MyBinaryTreeNodeG<T> right;
public MyBinaryTreeNodeG(T data){
this.data = data;
}
public MyBinaryTreeNodeG<T> addChild(T data){
if (data.compareTo(this.data) <= 0) {
//left node stuff
} else {
//right node stuff
return null;
}

If something is Comparable<T>, it is comparable to a T, not comparable to a Comparable<T>. That's why the second snippet works.

Look at the javadoc of Comparable : compareTo(T) is provided by the Comparable interface. This method allows to compare a object instance of T class implementing this interface with another T instance. In your first example, you're comparing a Comparable<T> with a Comparable<T> (and not with T)
This should work :
public class MyBinaryTreeNodeG<T> {
Comparable<T> data;
// ...
public MyBinaryTreeNodeG<T> addChild(final T data) {
if (this.data.compareTo(data) <= 0) {
} else {
}
// ...
}
}

Related

OOP: inheritance with recursive class definition

I have (recursively) defined a class for implementing a binary tree (in Java):
class BinaryTree {
protected int key;
protected BinaryTree left, right;
// some methods...
}
from which I want to implement a binary search tree, like this:
class BinarySearchTree extends BinaryTree {
// ...
public BinarySearchTree search(int x) {
if (x == key)
return this;
if (x < key)
if (left != null)
return left.search(x); // (*)
else
if (right != null)
return right.search(x); // (*)
return null;
}
}
but of course the lines marked with // (*) won't compile beacause left and right are just BinaryTrees, without any search() method.
So I am wondering if theres is a way to define BinarySearchTree from the BinaryTree superclass but with left and right being actually BinarySearchTrees.
Or maybe there is a better way of implementing the relationship between binary trees and the search ones: should I define a separate Node class? should I use templates? should I avoid recursive definitions at all? ...
You can use recursive generics.
Define a recursive generic type variable, say, B:
class BinaryTree<B extends BinaryTree<B>> {
and make your fields of this type:
protected B left, right;
Then define:
class BinarySearchTree extends BinaryTree<BinarySearchTree> {
Now left and right are of type BinarySearchTree too, allowing you to call left.search and right.search.
I feel BinaryTreeNode should be created as an inner class ofBinaryTree.java. BinaryTreeNode can have int data, and two references of type BinaryTreeNode for left and right node
BinaryTree.java should have an reference of type BinaryTreeNode which will be the root of the tree.
Now BinarySearchTree extends BinaryTree looks good, you can include an method in it as below signature.
BinaryTreeNode `search( int k, BinaryTreeNode root)`
Now you can define the recursive method.
Please see Sample code with basic skeleton.
BinaryTreeNode.java
public class BinaryTreeNode {
private int data;
private BinaryTreeNode left, right;
public BinaryTreeNode(int data) {
this.setData(data);
}
public BinaryTreeNode getLeft() {
return left;
}
public void setLeft(BinaryTreeNode left) {
this.left = left;
}
public BinaryTreeNode getRight() {
return right;
}
public void setRight(BinaryTreeNode right) {
this.right = right;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
BinaryTree.java
public class BinaryTree {
protected BinaryTreeNode root;
// other basic methods needed for creating the Binary tree.
}
BinarySearchTree.java
public class BinarySearchTree extends BinaryTree {
public BinaryTreeNode search(int k) {
return search(k, root);
}
private BinaryTreeNode search(int k, BinaryTreeNode root) {
if (root.getData() == k) {
return root;
}
if (root.getData() < k) {
return search(k, root.getRight());
} else {
return search(k, root.getLeft());
}
}
// add other methods needed for creating the Binary search tree.
// also override the methods which needs to be modified for their behavior
// for binary search tree
}

Problems converting Integer object to type int [duplicate]

This question already has answers here:
Java class with concrete type as parameter
(2 answers)
Closed 7 years ago.
Not sure what is going on here. Seems like an auto-boxing problem but I've been stuck on this for awhile and thought it might benefit me to stop stressing out and get some more experienced hands on this. The assignment is essentially implementing a BST and extending it to an implementation of an AVL and then running performance tests. To simplify things we can stick with using Integer as the generic.
The problem I am having is when comparing two Nodes. Autoboxing is not taking place and the intValue() method is not recognized.
public class BinaryNode<Integer> implements Comparable<Integer>
{
Integer data;
BinaryNode<Integer> leftChild;
BinaryNode<Integer> rightChild;
int height;
BinaryNode(Integer data)
{
this(data, null, null);
}
BinaryNode(Integer data, BinaryNode<Integer> lt, BinaryNode<Integer> rt)
{
this.data = data;
this.leftChild = lt;
this.rightChild = rt;
}
public Integer getData()
{
return this.data;
}
public BinaryNode<Integer> getLeft()
{
return leftChild;
}
public void setLeft(BinaryNode newNode)
{
this.leftChild = newNode;
}
public BinaryNode<Integer> getRight()
{
return rightChild;
}
public void setRight(BinaryNode newNode)
{
this.rightChild = newNode;
}
#Override
public int compareTo(BinaryNode<Integer> otherNode)
{
return this.getData() - otherNode.getData();
}
}
Edit: Thanks for the quick feedback. It was just the sort of interaction I needed to look at this differently and understand the quirky behavior I was encountering. Unfortunately I am bound to make this BinaryNode a generic class but the trick was to swap out all of the with or as the book's conventions prefer to use .
The best solution was to change the BinaryNode<Integer> to BinaryNode<AnyType> and remove the compareTo from this class. Now that I am no longer overshadowing java.lang.Integer I can reliably use the Integer.compareTo method as I originally intended.
For the curious, here is the TreePrinter class that I have to interact with that uses the parameterized BinaryNode class. http://www.cs.sjsu.edu/~mak/CS146/assignments/3/TreePrinter.java
In class BinaryNode<Integer>, Integer is a generic type parameter, not the Integer class.
change
public class BinaryNode<Integer> implements Comparable<Integer>
to
public class BinaryNode implements Comparable<Integer>
And change any appearance of BinaryNode<Integer> to BinaryNode.
If you wanted the BinaryNode class to takes a generic data type, you wouldn't write code specific to Integer data type (for example, return this.getData() - otherNode.getData() will never compile if getData() returns some generic type parameter T).
public class BinaryNode<Integer> implements Comparable<Integer>
Says that you have a new generic type named Integer. This is not the java.lang.Integer. This is why you're having issues, because they are completely different.
As Soritos Delimanolis pointed out, it would be better to just drop the generic type altogether.

From a Generic Tree To a Domain Specific Tree

I want to use a domain specific tree DomainTree consisting of Domain specific Nodes DomainNode, but keep all generic functions in template classes Tree and Node. First I started with the templates Tree<T> and Node<T> (where T is the type of a nodes data). The DomainTree was then working with the Node<T> interface, which was not what I wanted. It should work on DomainNode objects instead.
To cope with that, I changed the generic tree's template parameter to Tree<N extends Node<?>> (the implementation below). Now I can work with the DomainNode by instantiating the tree as DomainTree<DomainNode>.
Still, I get a compilation error at (1) because getChildren() returns a list of Node<T>, which doesn't seem to be convertible to a list of N, though I made sure that N extends Node<?>.
Why is this not working and how can I design it, so that the DomainTree can work with DomainNodes?
Generic Tree
import java.util.ArrayList;
import java.util.List;
class Tree<N extends Node<?>> {
public N rootElement;
public List<N> toList() {
List<N> list = new ArrayList<N>();
walk(rootElement, list);
return list;
}
private void walk(N element, List<N> list) {
list.add(element);
List<N> children = element.getChildren(); // (1) Cannot convert from List<Node<T>> to List<T>
for (N data : children) {
walk(data, list);
}
}
}
class Node<T> {
public T data;
public List<Node<T>> children;
public List<Node<T>> getChildren() {
if (this.children == null) {
return new ArrayList<Node<T>>();
}
return this.children;
}
public void addChild(Node<T> child) {
if (children == null) {
children = new ArrayList<Node<T>>();
}
children.add(child);
}
}
Problemspecific Tree
class DomainTree extends Tree<DomainNode> {
public void build() {
for (DomainNode node : toList()) {
// process...
}
}
}
class DomainNode extends Node<String> {
}
The problem with the code as it stands is that for a given Node<T>, the compiler has no way of knowing that the type of the List returned from toList() is the same Node<T> as the class itself.
What you need is a self-referencing generic type:
class Node<T, N extends Node<T, N>> {
public T data;
public List<N> children;
public List<N> getChildren() {
return children == null ? Collections.<N>emptyList() : children;
}
public void addChild(N child) {
if (children == null) {
children = new ArrayList<N>();
}
children.add(child);
}
}
Now the type returned from toList() is the same type as the type itself.
Then DomainNode becomes:
class DomainNode extends Node<String, DomainNode> {
//
}
And the signature of of Tree changes slightly to become:
class Tree<N extends Node<?, N>> {
And your usage example now compiles:
class DomainTree extends Tree<DomainNode> {
public void build() {
for (DomainNode node : toList()) {
// process...
}
}
}
I added in a couple of other efficiencies too.
generics hold some surprises if you are not really into it. At first keep in mind that there is a type erasure and the compiler and the runtime thus see different things. Roughly spoken this also limits the compiler abilities in analyzing source code.
Note that there is really a difference between a List<Node<N>> and a List<N>. Hence even with N extends Node<?> the assignment 'List children = element.getChildren();' is inherently broken.
Furthermore with your declaration of Tree<N extends Node<?>>, you would expect that you can write something like List<Node<?>> l2 = element.getChildren();. Unfortunately this does not work due to some subleteties of generics. For example if you change your code to class Tree<N extends Node<N>> (this is probably not what you intended) you can write List<Node<N>> l2 = element.getChildren();.
I recommend to study the Sun Certified Java Programmer Study Guide for Java 6 (or a newer version) or something similar which is really helpful about generics.
From your code I got the impression that you mix different abstraction layers as there is the T data in the Node<T> class and in the for each loop the element is called N data. However in the loop you have a node N extends Node<?> which would be completely different from the T data. Hence the intention for your code remains a bit unclear for me. A working draft if your code as fixed version is here (Eclipse Luna, JDK 6)
package generics.tree;
import java.util.ArrayList;
import java.util.List;
class Tree<T> {
public Node<T> rootElement;
public List<Node<T>> toList() {
List<Node<T>> list = new ArrayList<Node<T>>();
walk(rootElement, list);
return list;
}
private void walk(Node<T> element, List<Node<T>> list) {
list.add(element);
List<Node<T>> children = element.getChildren(); // (1) Cannot convert from List<Node<T>> to List<T>
for (Node<T> data : children) {
walk(data, list);
}
}
}
class Node<T> {
public T data;
public List<Node<T>> children;
public List<Node<T>> getChildren() {
if (this.children == null) {
return new ArrayList<Node<T>>();
}
return this.children;
}
public void addChild(Node<T> child) {
if (children == null) {
children = new ArrayList<Node<T>>();
}
children.add(child);
}
}
class DomainTree extends Tree<String> {
public void build() {
for (Node<String> node : toList()) { // changed!
// process...
}
}
}
class DomainNode extends Node<String> {
}

Generic Iterator implementation in java

I have the following design:
I have an Abstract class Instance,
I have a class Library that extends Instance and
I have a class File that also extends Instance
I've created my own linked list implementation and it's defined as follows:
public class List<T extends Instance> implements Iterable {
//some other code here
public Iterator iterator(){
return new ListIterator(this);
}
now I've created a class
public class ListIterator<T extends Instance> implements Iterator<T> {
private List thisList;
private Node current;
public ListIterator(List l){
thisList=l;
current=thisList.head.next;
}
#Override
public boolean hasNext() {
if(current==null)
return false;
return false;
}
#Override
public T next() {
Node temp=current;
current=current.next;
return temp.data;
}
}
Where Node is
public class Node<T extends Instance> {
public Node<T> next;
public Node<T> prev;
public T data;
public Node(T data,Node prev, Node next){
this.data=data;
this.prev=prev;
this.next=next;
}
}
so my problem is as follows: the line return temp.data rises an error:
Type mismatch - cannot convert from Instance to T.
What is wrong with this code?
I'd say that Node.data is a reference to an Instance object? If that is the case, the compiler can't automatically change an Instance to a T, because even though T is an Instance object (T extends Instance), any given Instance might not be a T.
The Java Generics tutorial explains it: http://docs.oracle.com/javase/tutorial/extra/generics/subtype.html
Also, in your List<T> class, you should be specifying Iterator and ListIterator as generic using Iterator<T> and ListIterator<T>, or else the compiler won't be able to handle the generics properly. Your Node reference also needs to be generic: Node<T>
Hence you should be using
private Node<T> current;
and
public T next() {
Node<T> temp=current;
current=current.next;
return temp.data;
}
The compiler will usually warn you when you're using a raw type for a generic class.
Did no one notice the bug:
public boolean hasNext() {
if(current==null)
return false;
return false;
}
This is an invariant. Unless I am missing something, the iterator will very quickly return 0 elements!

using compareTo in Binary Search Tree program

I've been working on this program for a few days now and I've implemented a few of the primary methods in my BinarySearchTree class such as insert and delete. Insert seemed to be working fine, but once I try to delete I kept getting errors. So after playing around with the code I wanted to test my compareTo methods. I created two new nodes and tried to compare them and I get this error:
Exception in thread "main" java.lang.ClassCastException: TreeNode cannot be cast to java.lang.Integer
at java.lang.Integer.compareTo(Unknown Source)
at TreeNode.compareTo(TreeNode.java:16)
at BinarySearchTree.myComparision(BinarySearchTree.java:177)
at main.main(main.java:14)
Here is my class for creating the nodes:
public class TreeNode<T> implements Comparable
{
protected TreeNode<T> left, right;
protected Object element;
public TreeNode(Object obj)
{
element=obj;
left=null;
right=null;
}
public int compareTo(Object node)
{
return ((Comparable) this.element).compareTo(node);
}
}
Am I doing the compareTo method all wrong? I would like to create trees that can handle integers and strings (seperatly of course)
To be sure that the element indeed is a comparable object, and avoid all the casts, you could do something like this:
public class TreeNode<T extends Comparable<? super T>>
implements Comparable<TreeNode<T>> {
protected TreeNode<T> left, right;
protected T element;
public TreeNode(T obj) {
element = obj;
left = null;
right = null;
}
#Override
public int compareTo(TreeNode<T> node) {
return element.compareTo(node.element);
}
}
For an usage example:
TreeNode<Integer> node1 = new TreeNode<Integer>(2);
TreeNode<Integer> node2 = new TreeNode<Integer>(3);
System.out.println(node1.compareTo(node2));
The above snippet prints -1 on the console.
compareTo method is applied against TreeNode (passed as node parameter), while you compare it with this.element, which is an Object contained in the TreeNode. Simply change to:
return ((Comparable) this.element).compareTo(node.getElement());
assuming you have getElement method.
Try
public <T> int compareTo(Object node)
{
return ((Comparable) this.element).compareTo( ( TreeNode<T> ) node ).element);
}

Categories