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(); } } ```