/* SortClass contains a merge sort method that can be used to sort data in a linked list. It uses to private methods, one to find the middle of the list and the other to merge two partial lists to create a full list. */ public class SortClass
{
    /* mergeLists has as parameters the list heads of the two lists to be merged. It changes the links on the two lists in order to make them into a single sorted list. */

    private Node mergeLists (Node first, Node second)
    {
        Node head, tail;
        if (second == null) // The second list is empty; return the first list.
            head = first;
        else if (first == null) // The first list is empty; return the second list.
            head = second;
        else // Neither list is empty, so set the head and tail to the smaller list head.
        {
            if (first.getId ().compareTo (second.getId ()) < 0)
            {
                head = first;
                tail = first;
                first = first.getNext ();
            } // if
            else
            {
                head = second;
                tail = second;
                second = second.getNext ();
            } // else
            while ((first != null) && (second != null)) // Merge the two lists until one becomes empty.
            {
                if (first.getId ().compareTo (second.getId ()) < 0)
                {
                    tail.setNext (first);
                    tail = first;
                    first = first.getNext ();
                } // if
                else
                {
                    tail.setNext (second);
                    tail = second;
                    second = second.getNext ();
                } // else
            } // while
            if (first == null) // If the first list is finished, attach the rest of the second list.
                tail.setNext (second);
            else // Attach the remainder of the first list.
                tail.setNext (first);
            } // else
            return head; // head points to the beginning of the combined lists.
        } // method merge

    /* The method, doubleTime, sends the second pointer through the list twice as fast as the first. When the second one is null, it moves it to the node immediately following the first node and then sets the next field of the first node to null. This breaks the list into two lists. These are either the same size if the original list had an even number of nodes. Otherwise the first list has one more node than the second. */

    private Node doubleTime (Node head)
    {
        Node first = head, second;
        if ((first != null) && (first.getNext () != null)) // The list has at least two nodes.
        {
            second = first.getNext (); // This puts second one node ahead of first to begin with.
            while (second != null)
            {
                second = second.getNext (); // This puts second either at the next node or makes it null.
                if (second != null)
                {
                    first = first.getNext (); // If second did not become null, first is advanced.
                    second = second.getNext (); // Second is kept two ahead of first with this.
                }
            }
            second = first.getNext ();
            first.setNext (null);
            return second;
        }
        else // Either the original list was empty or had just one node.
            return null;
    } // method doubleTime

    /* The mergeSort method uses recursion to successively divide the lists into halves. When the lists consist of single nodes, they are then merged two at a time to create the final sorted list. */

    public Node mergeSort (Node head)
    {
        if ((head != null) && (head.getNext () != null)) // The list contains at least two nodes.
        {
            Node first = head;
            Node second = doubleTime (head); // Find the middle of the list and break the list into two.
            first = mergeSort (first);
            second = mergeSort (second);
            head = mergeLists (first, second);
        }
        return head;
    } // method mergeSort
} // class SortClass