Search code examples
javagenericsheapheapsort

How to use compareTo with T Java generic?


I am trying to use compareTo with Java generic, but it keeps giving me an error. I then implemented

public interface Comparable<T> {
    int compareTo(T o);
}

But still did not help. The compiler keeps suggesting me to use private void heap_Rebuild(int ar) Here is my code:

 private void heap_Rebuild(T[] ar, int root, int size) {

    int child =2*root+1;
    if(child<size){
        int rightChild=child+1;

        if((rightChild<size)&& (ar[rightChild].compareTo(ar[rightChild])>0)){
            child=rightChild;
        }
        if(ar[root].compareTo(ar[child])<0){
            T temp=ar[root];
            ar[root]=ar[child];
            ar[child]=temp;
            heap_Rebuild(ar,child,size);
        }
    }

Rest of the code:

public class HeapSort<T> implements Function<T, U> {

protected Comparator<T> c;
@SuppressWarnings("unchecked")
public HeapSort() {
    this.c = (e1, e2) -> ((Comparable<T>)e1).compareTo(e2);

}

/** Create a BST with a specified comparator */
public HeapSort(Comparator<T> c) {
    this.c = c;

}

public   void sort(T[] anArray) {
    for(int index = anArray.length-1; index >=0; --index) {
        heapRebuild(anArray,index,anArray.length);

    }
    heapSort(anArray);
}

private void heapSort(T[] anArray) {
    // Left as an exercise

    int arrayLength=anArray.length;
    int index, step;
    for (index = arrayLength-1; index >=0; index--) {
        heapRebuild(anArray,index,arrayLength);
    }

    int last=arrayLength-1;
    for(step=1; step<=arrayLength;step++){
        int temp=last;
        anArray[last]=anArray[0];
        anArray[0]=anArray[temp];
        last--;
        heapRebuild(anArray,0,last);
    }

}

Any suggestions?


Solution

  • You need to set a bound for type variable T so that objects of that type are guaranteed to have the .compareTo method.

    public class HeapSort<T extends Comparable<? super T>> implements Function<T, U>
    

    It sounds like you defined your own Comparable<T> interface, but that T is unrelated, a generic type variable only applies within the class or method where it's defined. You should delete that extra Comparable<T> interface.


    Alternately, if you want to be able to use non-comparable types for T, your idea of using a Comparator<T> is correct, but your default implementation will not work:

    this.c = (e1, e2) -> ((Comparable<T>)e1).compareTo(e2);
    

    If T is not already a comparable type, the cast to Comparable<T> will fail. I would suggest not having a default constructor and always passing in a Comparator<T>. When using a type that is comparable, you can pass it Comparator.naturalOrder().

    You can use the comparator to replace the compareTo calls:

    if((rightChild<size)&& (c.compare(ar[rightChild],ar[rightChild])>0)){
    
    if(c.compare(ar[root],ar[child])<0){