Search code examples
javacollectionslinked-listdoubly-linked-list

Why is there not a LinkedList.join() method to merge two unsorted lists in O(1) time?


I'm no data structures expert, but as I understand it linked lists have proven to be quite inefficient in most scenarios mostly due to cache misses. One of the few reasons I would ever consider using them is for the unique ability to merge/split two of them in constant time; yet the class doesn't provide such a method.

I thought, all right, I will implement my own to fit my needs. I wanted the new class to follow the Collections framework API so I had it implement and extend the very same classes the standard LinkedList did. Soon I realized that I was just recreating LinkedList and all of this was pointless. At that point I might as well just copy paste the code and add the methods that I need.

On the same note, I can't find a reason (besides perhaps thread-safety which I am far from fully grasping yet) why there isn't such a method. Everything seemed like a standard linked list implementation and a method similar to splice() from the C++ STL could fit in there.

Am I missing something?

LinkedList<Integer> list1 = new LinkedList();
list1.add(4); 
list1.add(2);
list1.add(7);
// list1 = {4 , 2 , 7}

LinkedList<Integer> list2 = new LinkedList();
list2.add(9);
list2.add(4);
list2.add(6);
// list2 = {9 , 4 , 6}

list1.join(list2); // in O(1)
// at this point list2 should be invalidated/empty
// list1 = {4 , 2 , 7 , 9 , 4 , 6}
// list2 = {}

Solution

  • Java's implementation of native linkedlist has issues. There's no way to move nodes within a list or between lists, no equivalent to C++ std::list::splice(). All iterators to a link list become invalidated if there is an insertion or a deletion of a node anywhere in a linked list, except for the case where delete is done using an iterator parameter, in which case all iterators but the one used to do the insert or delete are invalidated. Iterators can't be shallow copied, assignment just points the destination iterator to the same iterator object pointed to by the source iterator.

    These issues make operations like merging or merge sort difficult, even more so for an iterator based operation.

    In the case of Visual Studio C++ std::list, deletion of nodes only invalidates iterators to deleted nodes, and only in a debug build. In a release build, no iterators are invalidated, and it's up to the programmer to ensure deleted nodes don't result in iterators pointing to deleted objects.


    As for why Java's native linkedlist has these limitations, Sun's stated reason at the time is they wanted a "compact framework" rather than be consistent with C++, which predates Java collections by 4 years (1998 for Java collections, 1994 HP copyright date shown at the end of most or all STL include files in the case of Visual Studio 2005 and prior versions of Microsoft and other C++ compilers). This is in spite of the fact that one of the predecessors to collections, JGL, did have the goal of being consistent with C++.

    https://en.wikipedia.org/wiki/Java_collections_framework#History

    There are other criticisms of Java, such as not having unsigned integers, treating primitives and objects differently, with a limited set of operations for primitives, ...