Reputation: 53
I've tried to write a Mergesort Algorithm in Java:
static void merge(int[] sort, int l, int m, int r) {
int[] cache_array = new int[r - l + 1];
int l_cache = l;
int _mid = m + 1;
for (int i = 0; i < r - l + 1; i++) {
if (l > m) {
cache_array[i] = sort[_mid];
_mid++;
} else { if (_mid > r) {
cache_array[i] = sort[l];
l++;
} else { if (sort[l] >= sort[_mid]) {
cache_array[i] = sort[l];
l++;
} else { if (sort[_mid] > sort[l]) {
cache_array[i] = sort[_mid];
_mid++;
}}}}
}
for (int i = 0; i < cache_array.length; i++) {
sort[i + l_cache] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (l < r) {
int mid = (int)Math.floor((l + r - 1) / 2);
mergeSort(sort, l, mid);
mergeSort(sort, mid + 1, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length - 1);
for (int i : a) {
System.out.println(i);
}
}
But it just sorts a part of the Array and replaces the rest of it with zeros. I tried to change the cache_array to a LinkedList but nothing changed and after I tried debugging I couldn't find out anything, too. I'd appreciate it if you'd help me and/or show me another Mergesort Algorithm that works for Java. (I used this Algorithm because it worked for Python and so I wanted to use similar code in Java)
Upvotes: 1
Views: 214
Reputation: 192
I usually implement it like this:
/// <summary>
/// Mergesort
/// best-case: O(n* log(n))
/// average-case: O(n* log(n))
/// worst-case: O(n* log(n))
/// </summary>
/// <returns>The sorted array.</returns>
/// <param name="array">array.</param>
public static int[] MergeSort(int[] array) {
// Exit condition for recursion
if (array.length <= 1) return array;
// Middle index of list to sort
int m = array.length / 2;
// Define left and right sub-listså
int[] left_array = new int[m];
int[] right_array = new int[array.length - m];
// Initialize left list
for (int i = 0; i < m; i++) left_array[i] = array[i];
// Initialize right list
for (int i = m, x = 0; i < array.length; i++, x++) right_array[x] = array[i];
// Recursively sort left half of the list
left_array = MergeSort(left_array);
// Recursively sort right half of the list
right_array = MergeSort(right_array);
// Merge sorted sub-lists
return Merge(left_array, right_array);
}
/// <summary>
/// Merge the specified left_array and right_array.
/// </summary>
/// <returns>The merge.</returns>
/// <param name="left_array">Left array.</param>
/// <param name="right_array">Right array.</param>
public static int[] Merge(int[] left_array, int[] right_array) {
int[] m = new int[left_array.length + right_array.length];
int index_l = 0;
int nl, nr;
nl = left_array.length - 1;
nr = right_array.length - 1;
for (int i = 0; i <= nl + nr + 1; i++) {
if (index_l > nl) {
m[i] = (right_array[i - index_l]);
continue;
}
if (index_l < i - nr) {
m[i] = (left_array[index_l]);
index_l++;
continue;
}
if (left_array[index_l] <= (right_array[i - index_l])) {
m[i] = (left_array[index_l]);
index_l++;
} else {
m[i] = (right_array[i - index_l]);
}
}
return m;
}
A few months ago I wrote all of the common sorting algorithms and this is what I got. A bit inaccurate but just to See how this implementation performs. The other algorithms are here.
To achieve a descending order I think you just have to swap the comparison operators.
Upvotes: 1
Reputation: 144750
The bug in your code is difficult to spot:
merge
function iterates for i
from 0
to r - l + 1
excluded, which would be correct if r
and l
remained constant during the loop, but you increment l
each time you copy from the left part, reducing the number of iterations. As a consequence, the loop exits early, leaving the remaining elements in cache_array
with their default value 0
.There are multiple sources of confusion in the code:
r
in the slice is confusing: it requires +1
/-1
adjustments to compute the slice lengths and the middle index.Math.floor()
is useless: integer arithmetic uses integer division in java.l
and m
arguments is confusing as these lose their meaning if the value is changed. Use other index variables to iterate through the arrays.{
between the else
and if
keywords introduces unnecessary indentation levels.cache_array
would be left untouched. This last condition would cause errors in this case.Here is a modified version:
// merge adjacent slices of the `sort` array.
// left slice has elements from `l` included to `m` excluded
// right slice has elements from `m` included to `r` excluded
static void merge(int[] sort, int l, int m, int r) {
int len = r - l;
int[] cache_array = new int[len];
for (int i = 0, ll = l, mm = m; i < len; i++) {
if (ll >= m) {
cache_array[i] = sort[mm];
mm++;
} else
if (mm >= r) {
cache_array[i] = sort[ll];
ll++;
} else
if (sort[ll] >= sort[mm]) {
cache_array[i] = sort[ll];
ll++;
} else {
cache_array[i] = sort[mm];
mm++;
}
}
for (int i = 0; i < len; i++) {
sort[l + i] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (r - l > 1) {
int mid = l + (r - l) / 2;
mergeSort(sort, l, mid);
mergeSort(sort, mid, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length);
for (int i : a) {
System.out.println(i);
}
}
Upvotes: 2
Reputation: 46
This is how I write the mergesort algorithm.
public static int[] mergeSort(int[] sort) {
if(sort.length > 1) {
int mid = sort.length / 2;
int[] left = Arrays.copyOf(sort, mid);
int[] right = Arrays.copyOfRange(sort, mid, sort.length);
// sort the left and right arrays
mergeSort(left);
mergeSort(right);
// Merge the arrays
merge(sort, left, right);
}
}
private static void merge(int[] sort, int[] leftArray, int[] rightArray) {
// These values are just to keep track of our position in each of the 3
// arrays
int l = 0; // left array
int r = 0; // right array
int o = 0; // the actual array being sorted
while(l < leftArray.length && r < rightArray.length) {
if(leftArray[l] < righArray[r]) {
sort[o++] = leftArray[l++];
}
else {
sort[o++] = leftArray[r++];
}
}
// Now that we are out of the while loop we know that either the
// left or right array has all of its values in sort, so we just
// need to put the rest of the values in the array that doesn't have
// all of its elements in sort with the following code.
while(l < leftArray.length) {
sort[o++] = leftArray[l++];
}
while(r < rightArray.length) {
sort[o++] = rightArray[r++];
}
}
Upvotes: 1