0

I couldn't figure out why my merge sort isn't working.

public static void merge(ArrayList<Coupon> arraylist, int LF, int LL, int RF, int RL) {
        ArrayList<Coupon> tempArr = arraylist;
        int i = LF;
        while (LF <= LL && RF <= RL) {
            if (arraylist.get(LF).getPrice() < arraylist.get(RF).getPrice()) {
                tempArr.Swap(i, LF);
                LF++;   
            } else {
                tempArr.Swap(i, RF);;
                RF++;
            }
            i++;
        }
        while (LF <= LL) {
            tempArr.Swap(i, LF);
            LF++;
            i++;
        }
        while (RF <= RL) {
            tempArr.Swap(i, RF);
            RF++;
            i++;
        }
        arraylist = tempArr;
    }
    
    public static void mergeSort(ArrayList<Coupon> arraylist, int first, int last) {
        if (first < last) {
            int middle = (first + last) / 2;
            mergeSort(arraylist, first, middle);
            mergeSort(arraylist, middle + 1, last);
            merge(arraylist, first, middle, middle+1, last);
        }
    }

I made sure I used it in my main class with correct parameters, I made sure the code actually looped through all the while loops and if-else statements(I checked with system out print in each statement), I also made sure that my Swap method is working by using it elsewhere. Can you help me find what went wrong? Thank you so much in advance!

P.S. LF is left first, LL is left last, RF is right first, RL is right last.

2 Answers2

0

The code is attempting to implement an in-place merge sort, which is more complicated than what the code is currently doing. For example, initial state, i = LF: assume the first compare is arraylist[LF] > arraylist[RF], so a swap of arraylist[i], arraylist[RF] where i == LF is done, then both i and RF are incremented, so what was in arraylist[LF] will end up getting skipped and never compared, when where it is possible that it should be at arraylist[LF+1], but is put at arraylist[RF] and never compared with any other element.

Normally a second array is allocated, and a merge sort merges between the two arrays:

https://en.wikipedia.org/wiki/Merge_sort#Top-down_implementation

Link to an example of an in-place but unstable (doesn't preserve original order of equal elements):

https://stackoverflow.com/a/15657134

rcgldr
  • 27,407
  • 3
  • 36
  • 61
0

Okay. First things first. You should really implement some kind of error checking in the mergeSort() method otherwise the compiler will throw a huge fit if any of the values end up being null or out of bounds. It's much easier to just catch those before they happen.

Secondly, I'm not entirely sure how your code works, since I can't be entirely sure what the getPrice() and swap() methods do. But, here is my implementation of mergeSort() that attempts to transfer some of your functionality over. Hopefully it helps you figure out what's going wrong. (P.S. this mergeSort() implementation was built originally with arrays in mind but it should work for lists too, it just might be more complex than it needs to be for lists)

public static <Coupon> List<Coupon> mergeSort(List<Coupon> l) {
    if (l == null) {
        throw new IllegalArgumentException();
    }
    if (l.size() < 2) { // You don't need to sort a 1 element list
        return l;
    }
    return merge(mergeSort(l.subList(0, (l.size() / 2)), 
            mergeSort(l.subList((l.size() / 2), l.size()));
}
public static <Coupon> List<Coupon> merge(List<Coupon> l1, List<Coupon> l2) {
    List<Coupon> lOut = new ArrayList<>();
    int index1 = 0;
    int index2 = 0;
    int indexOut;
    int totalLength = l1.size() + l2.size();
    for (indexOut = 0; indexOut < totalLength; indexOut++) {
        if (index1 == l1.size()) {
            lOut.set(indexOut, l2.get(index2);
            index2++;
        } else if (index2 == arr2.size()) {
            lOut.set(indexOut, l1.get(index1));
            index1++;
        } else if (l1.get(index1).compareTo(l2.get(index2)) <= 0) {
            lOut.set(indexOut, l1.get(index1));
            index1++;
        } else if (l1.get(index1).compareTo(l2.get(index2)) > 0 {
            lOut.set(indexOut, l2.get(index2));
            index2++;
        } else {
            throw new AssertionError(); // Code should *never* get here (hopefully)
        }
    }
    return lOut;
} 
ilanfriedman
  • 103
  • 1
  • 7
  • The OP's code is using swaps as if trying to implement an in place merge sort. Your code is using a second array lOut[], which is what a conventional merge sort does. – rcgldr Apr 26 '22 at 09:31
  • Ah. I now see that. If they were doing an in-place merge sort wouldn't it just be more efficient to implement insertion/bubble sort since then you can maximize speed instead of having the constant speed of mergesort? Or am I thinking about it wrong? – ilanfriedman Apr 27 '22 at 16:21
  • It's not clear if the OP intended to implement an in place mergesort, or it the OP was unaware that second array is normally used. In place merge sort would be faster than insertion sort, but much more complicated than normal merge sort. [github grail example](https://github.com/Mrrl/GrailSort/blob/master/GrailSort.h) . There are options in the code, like a small fixed size buffer or no buffer, and an alternative method, so the code is larger than it needs to be. – rcgldr Apr 27 '22 at 17:12