1
while (i < left.length && j < right.length) { if (left[i] <= right[j]) { result[z++] = left[i++]; } else { result[z++] = right[j++]; } } while (i < left.length) { result[z++] = left[i++]; // Why empty line right here?? } while (j < right.length) { result[z++] = right[j++]; }
You should not have an empty line before a closing brace, but you should have one immediately after a closing brace, so you should rewrite this to
while (i < left.length && j < right.length) { if (left[i] <= right[j]) { result[z++] = left[i++]; } else { result[z++] = right[j++]; } } while (i < left.length) { result[z++] = left[i++]; } while (j < right.length) { result[z++] = right[j++]; }
2
Add public
before static int[] mergeSort(int[] arr)
since you possibly want to expose your sort outside the current package.
3
In JDK, the convention is that all sort class methods do not return the array (they all are declared void
) but modify the contents of the input array.
4
Your implementation allocates \$\mathcal{O}(n \log n)\$ worth memory, whereas a linear space complexity suffices if you do a little trick (see Summa summarum). This slows down your algorithm since asking for memory is expensive, plus whenever we lose all references to an array, the garbage collector has to do additional work behind the scene in order to deallocate it.
What happens there, is that we allocate an auxiliary copy of the input array only once. Then, we distinguish two array roles: source anb target. Whenever merging, we read the data from source and put in sorted order to target. The actual mergesort routine alternates the roles of the arrays at each particular recursion level. This eliminates copying stuff in the merging routine, which increases performance.
Summa summarum
All in all, I had this in mind (rename if needed):
public static void coderoddeMergesort(final int[] array) { coderoddeMergesort(array, 0, array.length); } public static void coderoddeMergesort(final int[] array, final int fromIndex, final int toIndex) { if (fromIndex > toIndex) { throw new IllegalArgumentException( "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); } final int rangeLength = toIndex - fromIndex; if (rangeLength < 2) { // Trivially sorted. return; } // Allocate the auxiliary buffer only ONCE. final int[] aux = Arrays.copyOfRange(array, fromIndex, toIndex); // Do actual sorting. coderoddeMergesortImpl(aux, array, 0, rangeLength, fromIndex, toIndex); } private static void coderoddeMergesortImpl(final int[] source, final int[] target, final int sourceFromIndex, final int sourceToIndex, final int targetFromIndex, final int targetToIndex) { final int rangeLength = sourceToIndex - sourceFromIndex; if (rangeLength < 2) { return; } final int sourceMiddleIndex = sourceFromIndex + (rangeLength >>> 1); final int targetMiddleIndex = targetFromIndex + (rangeLength >>> 1); coderoddeMergesortImpl(target, source, targetFromIndex, targetMiddleIndex, sourceFromIndex, sourceMiddleIndex); coderoddeMergesortImpl(target, source, targetMiddleIndex, targetToIndex, sourceMiddleIndex, sourceToIndex); coderoddeMerge(source, target, targetFromIndex, sourceFromIndex, sourceMiddleIndex, sourceToIndex); } private static void coderoddeMerge(final int[] source, final int[] target, int targetOffset, int left, int right, final int rightBound) { final int leftBound = right; while (left < leftBound && right < rightBound) { target[targetOffset++] = source[left] < source[right] ? source[left++] : source[right++]; } System.arraycopy(source, left, target, targetOffset, leftBound - left); System.arraycopy(source, right, target, targetOffset, rightBound - right); }
(You can find a complete performance demonstration here.)
The performance figures are as follows:
coderoddeMergesort() in 1100 milliseconds. mergeSort() in 1412 milliseconds. Arrays are same: true
Hope that helps.
right
isarr.length
. Doesn't hurt anything but bigger than you intended I think.\$\endgroup\$right = new int[arr.length - arr.length / 2];
doesn't convey to those reading your code that the size is "the size of the remaining elements fromarr
". Something that would make it clear might beright = new int[arr.length - left.length];
\$\endgroup\$