Issues with generics < E > and < E extends Comparable > in code below. What changes are needed in the code below to prevent DLList.push_front() and DLList.push_back() from accepting strings instead of Integers?
The following code is a sub-set of C++ std::list, implemented as a circular double linked list that includes an internal node list where list.next is a reference to the first node, and list.prev is a reference to the last node. list is the equivalent of std::list::end(). References to nodes are used instead of std::list::iterator.
DLList.sort() is a recursive merge sort, but instead of scanning lists to split them, it recursively divides a count (size) by 2 until a base case of size == 1 is reached. DLList.merge() uses DLList.splice() to move one or more nodes at a time within a list to sort the list. Visual Studio 2022 now uses this method in std::list::sort(). On my old desktop with Intel 3770K CPU, it takes about 2 seconds to sort 4,194,304 Integers from sequentially allocated nodes, and about 3 seconds for scattered nodes (tested by refilling sorted list with random numbers and sorting again).
In the Visual Studio 2022 and my C++ implementations for std::list::sort() a pointer to the beginning node is passed by reference and a pointer to the ending node is returned. Java doesn't have pass by reference, so a static instance (one time allocation) of a node pair np is used instead, passed to and returned by sortr(). sortr() uses np.beg and sz as inputs, returns np, and only sets np.end in base cases where sz == 1.
I use one working directory with NetBeans, copying source files to x.java for testing, which is why package x is used.
package x;
import java.util.Random;
class DLNode<E>{
    DLNode<E> next;
    DLNode<E> prev;
    E element;
    DLNode(){
        next = null;
        prev = null;
        element = null;
    }
    DLNode(E e){
        next = null;
        prev = null;
        element = e;
    }
}
class NodePair{
    DLNode beg;
    DLNode end;
    NodePair(){
        beg = null;
        end = null;
    }
}
class DLList<E>{
    DLNode<E> list;
    int size;
    DLList(){
        list = new <E> DLNode();
        list.next = list;
        list.prev = list;
        size = 0;
    }
    public int size() {
        return size;
    }
    public DLNode<E> begin(){
        return list.next;
    }
    public DLNode<E> end(){
        return list;
    }
    public E front() {
        if(size == 0)
            return null;
        return (E) list.next.element;
    }
    public E back() {
        if(size == 0)
            return null;
        return (E) list.prev.element;
    }
    public void push_front(E element) {
        DLNode<E> node = new DLNode(element);
        size++;
        node.next = list.next;
        node.prev = list;
        list.next.prev = node;
        list.next = node;
    }
    public void push_back(E element) {
        DLNode<E> node = new DLNode(element);
        size++;
        node.next = list;
        node.prev = list.prev;
        list.prev.next = node;
        list.prev = node;
    }
    public E pop_front() {
        if(size == 0)
            return null;
        size--;
        DLNode<E> node = list.next;
        DLNode<E> next = node.next;
        next.prev = list;
        list.next = next;
        return (E) node.element;
    }
    public E pop_back() {
        if(size == 0)
            return null;
        size--;
        DLNode<E> node = list.prev;
        DLNode<E> prev = node.prev;
        prev.next = list;
        list.prev = prev;
        return (E) node.element;
    }
    // move rgt node to just before lft node
    public void splice(DLNode lft, DLNode rgt){
        rgt.prev.next = rgt.next;           // remove rgt node
        rgt.next.prev = rgt.prev;
        rgt.prev = lft.prev;                // insert before lft
        rgt.next = lft;
        lft.prev.next = rgt;
        lft.prev = rgt;
    }
    // move rgt to end.prev nodes to just before lft node
    public void splice(DLNode lft, DLNode rgt, DLNode end){
        DLNode lst = end.prev;              // reference to last node
        rgt.prev.next = end;                // remove rgt nodes
        end.prev = rgt.prev;
        rgt.prev = lft.prev;                // insert before lft
        lst.next = lft;
        lft.prev.next = rgt;
        lft.prev = lst;
    }
    // merge two sorted runs using splice to rearrange nodes within list
    private <E extends Comparable> DLNode<E> merge(DLNode<E> lft, DLNode<E> rgt, DLNode<E> end){
        DLNode<E> nxt;
        DLNode<E> rtn = lft;                // set reference to first merged node
        if(lft.element.compareTo(rgt.element) > 0)
            rtn = rgt;
        while(true){                        // merge runs
            // advance lft until lft > rgt
            while(lft.element.compareTo(rgt.element) < 1){
                lft = lft.next;
                if(lft == rgt)
                    return rtn;
            }
            // advance nxt undil nxt >= lft */
            nxt = rgt.next;
            while(nxt != end && nxt.element.compareTo(lft.element) < 1)
                nxt = nxt.next;
            // move rgt to nxt.prev to before lft
            splice(lft, rgt, nxt);
            rgt = nxt;
            if(rgt == end)
                return rtn;
        }
    }
    // merge sort using stack to track sorted run boundaries
    // lft and sz are local, np is one time allocation
    private NodePair sortr(NodePair np, int sz){
        if(sz == 1){
            np.end = np.beg.next;
            return np;
        }
        np = sortr(np, sz-sz/2);            // lft run
        DLNode lft = np.beg;
        np.beg = np.end;                    // rgt run
        np = sortr(np,    sz/2);
        np.beg = merge(lft,np.beg,np.end);  // merge
        return np;
    }
    public void sort(){
        if(size() < 2)
            return;
        NodePair np = new NodePair();
        np.beg = list.next;
        sortr(np, size);
    }
}
public class x {
    public static void main(String[] args) {
        DLList list = new <Integer> DLList();
        final int COUNT = 4*1024*1024;
        Random r = new Random();
        DLNode<Integer> node;
        Integer i;
        Integer j;
        long bgn, end;
        // test sort with sequentially allocated nodes
        for(i = 0; i < COUNT; i++)
            list.push_back((Integer)r.nextInt());
        bgn = System.currentTimeMillis();
        list.sort();
        end = System.currentTimeMillis();
        System.out.println("milliseconds " + (end-bgn));
        // test sort with scattered nodes
        for(node = list.begin(); node != list.end(); node = node.next)
            node.element = (Integer)r.nextInt();
        bgn = System.currentTimeMillis();
        list.sort();
        end = System.currentTimeMillis();
        System.out.println("milliseconds " + (end-bgn));
        // verify sort worked
        node = list.begin();
        i = node.element;
        j = i;
        for(node = node.next; node != list.end(); node = node.next){
            j = node.element;
            if(i.compareTo(j) > 0)
                break;
            i = j;
        }
        if(i.compareTo(j) == 0)
            System.out.println("passed");
        else
            System.out.println("failed");
        // remove all nodes from list
        while (0 != list.size())
            list.pop_front();
    }
}
```



