Search code examples
javasortingcomparable

Implement Comparable for generic Linked List for different classes


First of all: I'm not trying to re-invent the wheel, this is for purpose of study.

I'm quite a newbie in world so be patient.

My aim is to build a public class to manage linked list with sorted insertion.

What I did so far (that is working) is:

import java.util.Iterator;

import package_Car.SortTypes;

class Node<E>
{
    E data;
    Node<E> next;

    Node(E data, Node<E> node)
    {
        this.data = data;
        this.next = node;
    }

    public Node<E> getNext()
    {
        return next;
    }
}

public class SortedInsertionLinkedList<E> implements Iterable<Node<E>>
{
    Node<E> root;
    Sort_Types sort;

    final class LinkedListIterator implements Iterator<Node<E>>
    {
        private Node<E> cursor;

        LinkedListIterator(Node<E> root)
        {
            cursor = new Node<E>(null, null);
            cursor = root;
        }

        public boolean hasNext()
        {       
            return cursor != null;
        }

        public Node<E> next()
        {
            Node<E> retVal = cursor;

            if (hasNext())
            {
                cursor = retVal.getNext();
            }

            return retVal;      
        }
    }   

    public Iterator<Node<E>> iterator()
    {
        return new LinkedListIterator(root);
    }

    public SortedInsertionLinkedList(Sort_Types sort)
    {
        root = null;
        this.sort = sort;
    }

    public void insert(E item)
    {
        if (item != null)
        {
            if (root == null)
            {
                root = new Node<E>(item, null);
            }
            else
            {
                Node<E> currNode = root;
                Node<E> prevNode = null;

                for (Node<E> currListNode : this) 
                {
                    if (sort.compareTo(currListNode.data, item) < 0)
                    {
                        prevNode = currListNode;
                        currNode = currListNode.next;
                    }
                }

                Node<E> t = new Node<E>(item, currNode);

                if (prevNode == null)
                    root = t;
                else
                    prevNode.next = t;

            }
        }
    }

    public void print()
    {
        for (Node<E> currNode : this)
        {
            System.out.print(currNode.data + " ");
            System.out.println();
        }
        System.out.println();
    }

    public boolean find(E x)
    {
        for (Node<E> currNode : this)
        {
            int c = sort.compareTo(currNode.data, x);

            if (c == 0)
                return true;
            if (c > 0)
                return false;
        }
        return false;
    }

    public void delete(E x)
    {
        Node<E> prevNode = null;
        for (Node<E> currNode : this)
        {
            int c = sort.compareTo(currNode.data, x);
            if (c == 0)
            {
                if (currNode == root)
                {
                    root = currNode.next;
                }
                else
                {
                    prevNode.next = currNode.next;
                }

                return;
            }
            if (c > 0)
                return;

            prevNode = currNode;
        }
    }
}

As you can see I added to my class a private field that define which type of sort have to be used to compare linked list Nodes. This sort type is a enum

public enum Sort_Types
{
    SORT_BY_NAME
    {
        public int compareTo(Object o1, Object o2)
        {
            Car item1 = (Car) o1;
            Car item2 = (Car) o2;

            return item1.nome.compareTo(item2.nome);
        }
    },
    SORT_BY_PRICE
    {
        public int compareTo(Object o1, Object o2)
        {
            Car item1 = (Car) o1;
            Car item2 = (Car) o2;

            return Double.compare(item1.prezzo, item2.prezzo);
        }
    },
    SORT_BY_GAIN
    {
        public int compareTo(Object o1, Object o2)
        {
            double gain1;
            double gain2;

            if (o1 instanceof CarSpecificInterface)
            {
                CarSpecificInterface dummy = (CarSpecificInterface) o1;
                gain1 = dummy.gain();
            }
            else
            {
                throw new IllegalArgumentException();
            }

            if (o2 instanceof CarSpecificInterface)
            {
                CarSpecificInterface dummy = (CarSpecificInterface) o2;
                gain2 = dummy.gain();
            }
            else
            {
                throw new IllegalArgumentException();
            }

            return Double.compare(gain2, gain1);
        }
    },
    SORT_BY_URGENCY
    {
        public int compareTo(Object o1, Object o2)
        {
            double urgency1;
            double urgency2;

            if (o1 instanceof CarSpecificInterface)
            {
                CarSpecificInterface dummy = (CarSpecificInterface) o1;
                urgency1 = dummy.urgency();
            }
            else
            {
                throw new IllegalArgumentException();
            }

            if (o2 instanceof CarSpecificInterface)
            {
                CarSpecificInterface dummy = (CarSpecificInterface) o2;
                urgency2 = dummy.urgency();
            }
            else
            {
                throw new IllegalArgumentException();
            }        

            return Double.compare(urgency2, urgency1);
        }
    };

    public abstract int compareTo(Object o1, Object o2);
}

Why I did that? Because of class that can be used to instatiate the linked list are 3:

  1. Car
  2. New_Car that extends Car
  3. Used_Car that extends Car

New_Car and Used_Car classes implements an interface

public interface Car_Specific_Interface
{
    public double gain();
    public double urgency();
}

So I can use my linked list for type Car that can accept (obviously) SubClasses

Sorted_Linked_List<Car> carsSortedByName;
Sorted_Linked_List<Car> carSortedByGain;
Sorted_Linked_List<Car> carSortedByUrgency;

public DB_Mng()
{
    carsSortedByName = new Sorted_Linked_List<>(Sort_Types.SORT_BY_NAME);
    carSortedByGain = new Sorted_Linked_List<>(Sort_Types.SORT_BY_GAIN);
    carSortedByGain = new Sorted_Linked_List<>(Sort_Types.SORT_BY_URGENCY);
}

So, to sum up: I have a generic linked list with sorted insertion that can accept different classes and can be sorted by specific field or methods.

What I'd like to understand is if there is a way to do that changing classes hierarchy "simply" implementing Comparable interface.


Solution

  • Step one is to understand java generics. Specifically, java generics are a compile time feature; they are in no way a java implementation of c++ templates.

    You can not create a "fully general" sorted-on-insert list because Object does not implement any comparison functionality.

    You can create a sorted-on-insert list of elements that implement some known interface or which extend a specific class.