1

I want to sort a LinkedList in Java using a Mergesort algorithm.
I've researched in the internet for a solution but the algorithms I found sort either an Array or a self declared LinkedList. As I mentioned earlier I need an algorithm which sorts the standard java LinkedList (java.util.LinkedList).
In addition to my research I tried to implement one myself but I'm not capable of doing so. I was able to create the 'divide' part but I couldn't program the 'conquer' (merge in the sorted order) part.
This is my code:

private void mergeSort(LinkedList<Integer> list) {
        if (list.size() < 2){
            return;
        }
        int middleindex  = list.size()/2;
        LinkedList<Integer> [] listArr = split(list, middleindex);

        LinkedList<Integer> leftList = listArr[0];
        mergeSort(leftList);

        LinkedList<Integer> rightList = listArr[1];
        mergeSort(rightList);

        sortedMerge(rightList, leftList, list);

    }

    private void sortedMerge(LinkedList<E> right, LinkedList<E> left, LinkedList<E> list){
        //sort and merge
    }


    @SuppressWarnings("unchecked") private static <T> LinkedList<T>[] split(LinkedList<T> list, int index) {
        LinkedList<T> left = new LinkedList<>();

        for (int i = 0; i < index; i++) {
            T t = list.removeFirst();
            left.addLast(t);
        }
        return new LinkedList[] {
                left, list
        };
    }

Can someone help me and create the 'sortedMerge()' method?

Racecarver
  • 13
  • 2
  • Bottom up merge sort for linked list using a small array (26 to 32) of pointers, references, iterators, ... , is a bit faster than top down. [Wiki example](https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists) – rcgldr May 18 '19 at 21:23
  • Since Java doesn't include C++ iterators (pointers to nodes in the list) or std::list::splice(), the list can't be merge sorted "in place". An alternative for bottom up merge sort for linked lists is to use a small array of lists instead of pointers or references as shown in the wiki article. This is how Visual Studio prior to 2015 implemented std::list::sort(). If interested, I can post example code. It isn't as fast a a copy to array, sort the array, and create a new array from the sorted array, but it would be a true linked list sort. – rcgldr May 25 '19 at 01:55

2 Answers2

0

The Collections.sort() method sorts the LinkedList. It does so by copying the contents of LinkedList to an array, sorting the array, and copying the contents of array back to LinkedList. You can implement the same functionalities as the Collections.sort() method and use the merge sort algorithm to sort the array.

Below I have detailed my steps and correct code that sorts Java's standard LinkedList using Merge Sort algorithm.

Steps:

  1. Create a LinkedList 'orginialList'
  2. Convert 'originalList' to Integer array 'arr'
  3. Convert 'arr' to int array 'intArray'
  4. Sort 'intArray' using the merge sort algorithm
  5. Convert sorted 'intArray' back to Integer array 'arr' (use for loop to change elements in 'arr')
  6. Create a LinkedList 'newList'
  7. Add elements of 'arr' to 'newList' (use Arrays.asList(arr))
     public static class CollectionsSort {
         public static void main(String[] args) {
               LinkedList<Integer> originalList = new LinkedList<>();
               originalList.add(3);
               originalList.add(2);
               originalList.add(1);

               Integer[] arr = list.toArray(new Integer[list.size()]);
               int[] intArray = new int[arr.length];
               for (int i = 0; i < intArray.length; i++) {
                   intArray[i] = arr[i].intValue();
               }
               mergesort(intArray);
               for (int i = 0; i < arr.length; i++) {
                   arr[i] = new Integer(intArray[i]); 
               }
               LinkedList<Integer> newList = new LinkedList(Arrays.asList(arr));
               Iterator it = newList.iterator();
               while(it.hasNext()) {
                  System.out.print((int)(it.next()) + " ");
               }
         }

         public static int[] mergesort(int[] arr) {
               int low = 0;
               int high = arr.length-1;
               mergesort(arr, low, high);
               return arr;
         }

         public static void mergesort(int[] arr, int low, int high) {
               if (low == high) {
                   return;
               } else {
                   int middle = low + (high-low)/2;
                   mergesort(arr, low, middle);
                   mergesort(arr, middle+1, high);
                   merge(arr, low, middle, high);
               }
         }

         public static void merge(int[] arr, int low, int mid, int high) {
               int[] left = new int[mid-low+2];
               for (int i = low; i <= mid; i++) {
                   left[i-low] = arr[i];
               }
               left[mid-low+1] = Integer.MAX_VALUE;
               int[] right = new int[high-mid+1];
               for(int i = mid+1; i <= high; i++) {
                   right[i-mid-1] = arr[i];
               }
               right[high-mid] = Integer.MAX_VALUE;
               int i = 0, j = 0;
               for(int k = low; k <= high; k++) {
                   if(left[i] <= right[j]) {
                      arr[k] = left[i];
                      i++;
                   } else {
                      arr[k] = right[j];
                      j++;
                   }
               }
         }
     }
kundus
  • 121
  • 1
  • 6
  • I actually did it already like you suggested. I thought there was a 'more elegant' method like those using a custom LinkedList, but I think the standard LinkedList is too limited for that. Thank you anyways! – Racecarver May 22 '19 at 19:28
  • @Racecarver - It's not clear by what you mean by "more elegant". It is possible to merge sort a list using list containers instead of arrays for working storage, but it is slower. There isn't a way to merge sort a native Java linked list "in place" as there is with C++ std::list (unless indexing is used which is very inefficient, as it scans the list). – rcgldr May 26 '19 at 14:16
  • @rcgldr - I meant an in place merge sort like it is possible in c++. – Racecarver May 27 '19 at 15:15
  • @Racecarver - yes, that is how std::list::sort() and std::list::merge() operate. No nodes are created or deleted, just moved within a list or from one list to another. std::list::sort() or a programmer created merge sort for std::list can be implemented using iterators to point to nodes, either pushing them on the stack for [top down merge sort](https://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation_using_lists), or using a small (26 to 32) array of iterators for [bottom up](https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists). – rcgldr May 27 '19 at 15:28
  • @Racecarver - Visual Studio 2015 and later use top down approach with iterators. I posted example code of bottom up approach also using iterators towards the end of [this answer](https://stackoverflow.com/questions/40622430/stdlistsort-why-the-sudden-switch-to-top-down-strategy/40629882#40629882). – rcgldr May 27 '19 at 15:34
  • @rcgldr Thank you :) – Racecarver May 28 '19 at 16:13
  • @Racecarver - you could create a custom linked list class in Java to duplicate the features of std::list. – rcgldr May 28 '19 at 16:32
  • @rcgldr I know this possibility but I wanted to do it without a costum LinkedList. – Racecarver May 30 '19 at 13:28
  • @Racecarver - Java's native LinkedList doesn't have the equivalent of std::list::splice(), which moves nodes and is used by std::list::merge() and std::list::sort(). You could create a merge that works similar to your split function, but that is creating and deleting a node for every node "moved". – rcgldr May 30 '19 at 19:26
0

Example code (including test code in main()) for a bottom up merge sort for Java LinkedList, which uses a small array (32) of lists, (as opposed to top down's approach of splitting and pushing lists onto the stack). Since Java LinkedList doesn't have the C++ equivalent of std::list::splice(), which moves nodes within a list (or from list to list), the nodes and lists are created and deleted, which adds a significant amount of overhead.

package llsort;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Random;

public class llsort {

    public static LinkedList<Integer> Merge(LinkedList<Integer> ll0, LinkedList<Integer> ll1){
        LinkedList<Integer> ll = new LinkedList<>();
        if(ll0.isEmpty())               // empty list check
            return (ll1);
        if(ll1.isEmpty())
            return (ll0);
        ListIterator <Integer> ll0i = ll0.listIterator(0);
        ListIterator <Integer> ll1i = ll1.listIterator(0);
        Integer e0;
        Integer e1;
        e0 = ll0i.next();               // merge lists
        e1 = ll1i.next();
        while(true){
            if(e0 <= e1){
                ll.add(e0);
                if(ll0i.hasNext()){
                    e0 = ll0i.next();
                    continue;
                }
                ll.add(e1);
                while(ll1i.hasNext())
                    ll.add(ll1i.next());
                break;
            }else{
                ll.add(e1);
                if(ll1i.hasNext()){
                    e1 = ll1i.next();
                    continue;
                }
                ll.add(e0);
                while(ll0i.hasNext())
                    ll.add(ll0i.next());
                break;
            }
        }
        return ll;
    }

    public static LinkedList<Integer> MergeSort(LinkedList<Integer> src){
        final int NUMLIST = 32; 
        LinkedList<Integer>[] all = new LinkedList[NUMLIST];
        LinkedList<Integer> ll;
        int i;
        // merge nodes into array
        ll = new LinkedList();
        while(!src.isEmpty()){
            ll.add(src.peek());
            src.remove();
            for(i = 0; i < NUMLIST && all[i]!= null; i++){
                ll = Merge(ll, all[i]);
                all[i] = null;
            }
            if(i == NUMLIST)
                i--;
            all[i] = ll;
            ll = new LinkedList();
        }
        // merge array into list
        ll = new LinkedList();
        for(i = 0; i < NUMLIST; i++)
            if(all[i] != null)   
                ll = Merge(ll, all[i]);
        return ll;        
    }

    public static void main(String[] args) {
        final int NUMELEM = 2*1024*1024; 
        LinkedList<Integer> ll = new LinkedList<>();
        Random r = new Random();
        for(int i = 0; i < NUMELEM; i++)
            ll.addLast(r.nextInt());
        long bgn, end;
        bgn = System.currentTimeMillis();
        ll = MergeSort(ll);
        end = System.currentTimeMillis();
        System.out.println("milliseconds " + (end-bgn));
        // check sort
        while(true){
            int i = ll.peek();
            ll.remove();
            if(ll.isEmpty())
                break;
            if(i > ll.peek()){
                System.out.println("error");
                break;
            }
        }
    }
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61