MergeSort Algorithm from largest to smallest in java - java

So I want to use the mergesort algorithm to sort an array filled with numbers from largest to smallest. I have working code for this but I can't seem to make it sort from largest to smallest. I tried playing around with the for loop that has all of those if statements in there but I just couldn't figure it out. Could someone please help.
public class MergeSorter
{
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result+ i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] < second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}
import java.util.Arrays;
public class MergeSortTest
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}

Your entire logic is correct except one thing. In the sort_descend function, after you copy the array a into first_replace and second_replace, you start comparing the elements using the if condition if (first_replace[first_i] < second_replace[second_i]).
Here, you essentially assign the smaller of the two elements into your array a and this the step which determines whether your array will be sorted in ascending order or descending order.
To sort in descending order, you need to just reverse this sign and you will get the desired output i.e. change the if condition to if (first_replace[first_i] > second_replace[second_i]).

Please refer to the below code to sort an array of integers in descending order.
It is similar to your solution but only one change of the comparator operator on line number 38.
import java.util.Arrays;
public class C
{
public static void main(String args[]) {
int[] array = new int[]{ 6, 1, 3, 8, 3, 9, 2 };
MergeSorter ms = new MergeSorter();
ms.merge(array, 0, array.length - 1);
System.out.println(Arrays.toString(array));
}
}
class MergeSorter {
public void merge(int[] a, int l, int h) {
if (h <= l) return;
int result = (l + h) / 2;
merge(a, l, result);
merge(a, result + 1, h);
sort_descend(a, l, result, h);
}
public void sort_descend(int[] a, int l, int result, int h) {
int first_replace[] = new int[result - l + 1];
int second_replace[] = new int[h - result];
for (int i = 0; i < first_replace.length; i++)
first_replace[i] = a[l + i];
for (int i = 0; i < second_replace.length; i++)
second_replace[i] = a[result + i + 1];
int first_i = 0;
int second_i = 0;
for (int i = l; i < h + 1; i++) {
if (first_i < first_replace.length && second_i < second_replace.length) {
if (first_replace[first_i] >= second_replace[second_i]) {
a[i] = first_replace[first_i];
first_i++;
} else {
a[i] = second_replace[second_i];
second_i++;
}
} else if (first_i < first_replace.length) {
a[i] = first_replace[first_i];
first_i++;
} else if (second_i < second_replace.length) {
a[i] = second_replace[second_i];
second_i++;
}
}
}
}

Related

Mergesort Algorithm in Java

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)
The bug in your code is difficult to spot:
the loop in your 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:
the convention to include r in the slice is confusing: it requires +1/-1 adjustments to compute the slice lengths and the middle index.
using Math.floor() is useless: integer arithmetic uses integer division in java.
incrementing the 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.
adding a { between the else and if keywords introduces unnecessary indentation levels.
the last condition is the opposite of the previous one: you should just omit it. Note that if the array elements were floating point values, both conditions could be false for NaN values and some elements of 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);
}
}
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++];
}
}
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.

Even before odd that is in ascending order using recursion

I need to be able to have an array of integers that places even integers before odd integers then sort the array in ascending order. For instance given the array [1,2,3,4,5] the final product should look like [2,4,1,3,5] as you can see the array has both the evens before the odds and then places them in ascending order.
As you see in the code I am using the array [10,9,8,7,6,5,4,3,2,1]. The output I am getting is [1,2,3,4,5,6,7,8,9,10], but this is incorrect - it should be [2,4,6,8,10,1,3,5,7,9]. I cannot use any built in functions or libraries. Here is what I have so far:
public class EBOMain {
static int[] Array = { 10,9,8,7,6,5,4,3,2,1};
static int n;
public static void main(String[] args) {
System.out.print("Array before sort: " );
for (int i = 0; i < Array.length; i++)
System.out.print(Array[i] +" ");
n = Array.length;
EvenBeforeOdd(Array, n);
int[] Array2 = new int[Array.length];
MergeSort(Array2, 0,Array.length - 1);
System.out.print("\nArray after sort: " );
for (int i = 0; i < Array.length; i++)
System.out.print(Array[i] +" ");
}
public static void EvenBeforeOdd(int []Array,int n){
if (n==0)
return;
else if(Array[n-1]%2==0) {
for(int i=0;i<n-1;i++) {
if(Array[i]%2!=0) {
int temp = Array[i];
Array[i]= Array[n-1];
Array[n-1] = temp;
EvenBeforeOdd(Array,n-1);
}
}
}
else
EvenBeforeOdd(Array,n-1);
}
static void MergeSort(int[] Combine, int LowerIndex, int UpperIndex) {
if (LowerIndex == UpperIndex){
return;
}
else { // locate Pivot
int Pivot = (LowerIndex + UpperIndex) / 2;
MergeSort(Combine, LowerIndex, Pivot);
MergeSort(Combine, Pivot + 1, UpperIndex);
Merge(Combine, LowerIndex, Pivot + 1, UpperIndex);
}
}
static void Merge(int[] Array2, int Small, int Large, int UpperIndex) {
int Pivot = Large - 1;
int LowerIndex = Small;
int n = UpperIndex - LowerIndex + 1;
int i = 0;
while (Small <= Pivot && Large <= UpperIndex)
if (Array[Small] < Array[Large])
Array2[i++] = Array[Small++];
else
Array2[i++] = Array[Large++];
while (Small <= Pivot)
Array2[i++] = Array[Small++];
while (Large <= UpperIndex)
Array2[i++] = Array[Large++];
for (i = 0; i < n; i++)
Array[LowerIndex + i] = Array2[i];
}
}
You just need to call MergeSort twice. Determine where the last even number is, call MergeSort on the even numbers, then on the odds. There should be boundary checks in case there are no even numbers (not included here):
EvenBeforeOdd(Array, n);
int lastEven = 0;
for (int i=0; i<Array.length; i++) {
if (Array[i] % 2 == 0)
lastEven = i;
}
int[] Array2 = new int[Array.length];
MergeSort(Array2, 0, lastEven);
MergeSort(Array2, lastEven+1, Array.length - 1);
Below is one of possible solutions of this problem.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
class Main {
private static final int[] array = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
public static void main(String[] args) {
List<Integer> odd = new ArrayList<>();
List<Integer> even = new ArrayList<>();
for (int number : array) {
if (number % 2 != 0)
odd.add(number);
else
even.add(number);
}
Collections.sort(odd);
Collections.sort(even);
List<Integer> evenBeforeOdd = new ArrayList<>();
Stream.of(even, odd).forEach(evenBeforeOdd::addAll);
evenBeforeOdd.forEach(System.out::println);
// 2,4,6,8,10,1,3,5,7,9
}
}

Merge Sort Algorithm Code

This is code for Merge Sort using the Java programming language.
Where there is an error, it does not give me the correct output.
Is it possible to help me to resolve? Thank you.
I want to work with arrays of type integer.
import java.util.Arrays;
public class Excersize5 {
public void MergeSort(int[] Arr) {
int N = Arr.length;
if (N > 1) {
int Middle = (N) / 2;
int[] A1 = LeftElement(Arr);
int[] A2 = RightElement(Arr);
MergeSort(A1);
MergeSort(A2);
Merge(Arr, A1, A2);
}
}
public void Merge(int[] Result, int[] A1, int[] A2) {
int i = 0;
int j = 0;
for (int k = 0; k < Result.length; k++) {
if (A1[i] >= A2[j] || (i < A1.length &&
A1[i] <= A2[j])) {
Result[k] = A1[i];
i++;
} else {
Result[k] = A2[j];
j++;
}
}
}
public int[] LeftElement(int[] Total) {
int NL = Total.length / 2;
int[] L = new int[NL];
for (int p = 0; p < NL; p++) {
L[p] = Total[p];
}
return L;
}
public int[] RightElement(int[] Total) {
int NL = Total.length / 2;
int NR = Total.length - NL;
int[] R = new int[NR];
for (int q = 0; q < NR; q++) {
R[q] = Total[q];
}
return R;
}
public static void main(String[] args) {
Excersize5 e5 = new Excersize5();
int[] r = {5, 6, 7, 8, 1, 7};
e5.MergeSort(r);
System.out.print(r);
}
}
Output
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at practical4.Excersize5.Merge(Excersize5.java:22) at
practical4.Excersize5.MergeSort(Excersize5.java:14) at
practical4.Excersize5.MergeSort(Excersize5.java:13) at
practical4.Excersize5.MergeSort(Excersize5.java:12) at
practical4.Excersize5.main(Excersize5.java:55) Java Result: 1 BUILD
SUCCESSFUL (total time: 1 second)
You could just use a Vector instead will make it much easier to do. It's because your calling things outside your array length, all of them, and you never return the array result which you should do in some method

Void merge sort method java

So, my computer science teacher has told me to make every method here void, except for copyPartArray. I have no idea how to do this, when I try, the sort simply fails.
public static ArrayList<String> mergeSortHelper(ArrayList<String> a) {
int mid = a.size() / 2 - 1;
if (a.size() <= 1)
return a;
return merge(mergeSortHelper(copyPartArray(a, 0, mid)),
mergeSortHelper(copyPartArray(a, mid + 1, a.size() - 1)));
}
public static void mergeSort(ArrayList<String> a) {
ArrayList<String> x = mergeSortHelper(a);
for (int i = 0; i < a.size(); i++) {
a.set(i, x.get(i));
}
}
public static ArrayList<String> merge(ArrayList<String> a,
ArrayList<String> b) {
ArrayList<String> x = new ArrayList<String>(a.size() + b.size());
int aCount = 0;
int bCount = 0;
for (int i = 0; i < a.size() + b.size(); i++) {
if (aCount > a.size() - 1) {
for (int j = bCount; j < b.size(); j++) {
x.add(b.get(j));
}
break;
}
if (bCount > b.size() - 1) {
for (int j = aCount; j < a.size(); j++) {
x.add(a.get(j));
}
break;
}
if ((a.get(aCount)).compareTo(b.get(bCount)) < 0) {
x.add(a.get(aCount));
aCount++;
} else {
x.add(b.get(bCount));
bCount++;
}
}
return x;
}
public static ArrayList<String> copyPartArray(ArrayList<String> a, int s,
int e) {
ArrayList<String> x = new ArrayList<String>();
for (int i = s; i <= e; i++) {
x.add(a.get(i));
}
return x;
I have tried to change my mergeSort to:
public static void mergeSort(ArrayList<String> a) {
int mid = a.size() / 2 - 1;
if (a.size() <= 1)
return;
mergeSort(copyPartArray(a, 0, mid));
mergeSort(copyPartArray(a, mid + 1, a.size() - 1));
merge(a, copyPartArray(a, 0, mid),
copyPartArray(a, mid + 1, a.size() - 1));
}
and get rid of the mergeSortHelper all together.
Now I have:
public static void mergeSort(ArrayList<String> a, int start, int end) {
int mid = (start + end) / 2;
if (a.size() <= 1)
return;
mergeSort(a, start, mid);
mergeSort(a, mid + 1, end);
how would I incorporate my merge method into this?
copyPartArray is going to make a copy of the array so that's no good, your lecturer wants you to pass the array by reference and then also pass in the start/end (or start/length) integers. Try doing something like this:
public static void mergeSort(ArrayList<String> a, int start, int length) {
// refer to 'the array' as a[start] to a[start + length]
}
a will be passed by reference which means you don't need a return value.
So I would change your methods to take a start and length and get rid of copyPartArray all together, you can do your merging in-place on the one array.
I use this method in my blog post on Quicksort.

Java recursive insertion sort?

So I am trying to make the following code into a recursive method, insertion sort, but for as much as I try I cannot. Can anyone help me?
public static void insertionSort(int[] array){
for (int i = 1; i < array.length; i++){
int j = i;
int B = array[i];
while ((j > 0) && (array[j-1] > B)){
array[j] = array[j-1];
j--;
}
array[j] = B;
}
}
EDIT:
I was thinking of something like this, but it doesn't look very recursive to me...
public static void insertionSort(int[] array, int index){
if(index < array.length){
int j = index;
int B = array[index];
while ((j > 0) && (array[j-1] > B)){
array[j] = array[j-1];
j--;
}
array[j] = B;
insertionSort(array, index + 1);
}
}
Try this:
public class RecursiveInsertionSort {
static int[] arr = {5, 2, 4, 6, 1, 3};
int maxIndex = arr.length;
public static void main(String[] args) {
print(arr);
new RecursiveInsertionSort().sort(arr.length);
}
/*
The sorting function uses 'index' instead of 'copying the array' in each
recursive call to conserve memory and improve efficiency.
*/
private int sort(int maxIndex) {
if (maxIndex <= 1) {
// at this point maxIndex points to the second element in the array.
return maxIndex;
}
maxIndex = sort(maxIndex - 1); // recursive call
// save a copy of the value in variable 'key'.
// This value will be placed in the correct position
// after the while loop below ends.
int key = arr[maxIndex];
int i = maxIndex - 1;
// compare value in 'key' with all the elements in array
// that come before the element key.
while ((i >= 0) && (arr[i] > key)) {
arr[i+1] = arr[i];
i--;
}
arr[i+1] = key;
print(arr);
return maxIndex + 1;
}
// code to print the array on the console.
private static void print(int[] arr) {
System.out.println();
for (int i : arr) {
System.out.print(i + ", ");
}
}
}
public static void insertionSort(int[] array, int index) {
if(array.length == index + 1) return;
insertionSort(array, index + 1);
// insert array[index] into the array
}
You can try this code. It works correctly.
public static int[] InsertionSort(int[] dizi, int n)
{
int i;
if (n < 1) {
InsertionSort(dizi, n - 1);
}
else {
int key = dizi[n];
i = n - 1;
while (i >= 0 && dizi[i] > key) {
dizi[i + 1] = dizi[i];
i = i - 1;
}
dizi[i + 1] = key;
}
return dizi;
}
for the recursion algorithm, we start with the whole array A[1..n], we sort A[1..n-1] and then insert A[n] into the correct position.
public int[] insertionSort(int[] array)
{
//base case
if(array.length==1) return new int[]{ array[0] };
//get array[0..n-1] and sort it
int[] arrayToSort = new int[array.length - 1]{ };
System.arraycopy(array, 0, arrayToSort, 0, array.length -1);
int[] B = insertionSort(arrayToSort);
//now, insert array[n] into its correct position
int[] C = merge(B, array[array.length - 1]);
return C;
}
private int[] merge(int[] array, int n)
{
int[] arrayToReturn = new int[array.length + 1] {};
int j = array.length-1;
while(j>=0 && n <= array[j])
{
arrayToReturn[j+1]=array[j;
j--;
}
arrayToReturn[j] =
}
Try below code by providing ele as an integer array, sortedIndex=index of first element and index=index of second element:
public static void insertionSort(int[] ele, int sortedIndex, int index) {
if (sortedIndex < ele.length) {
if (index < ele.length) {
if (ele[sortedIndex] > ele[index]) {
ele[sortedIndex] += ele[index];
ele[index] = ele[sortedIndex] - ele[index];
ele[sortedIndex] = ele[sortedIndex] - ele[index];
}
insertionSort(ele, sortedIndex, index + 1);
return;
}
if (index == ele.length) {
sortedIndex++;
}
insertionSort(ele, sortedIndex, sortedIndex + 1);
}
}
public static void sort(int[] A, int p, int r) {
if (p < r) {
int q = r - 1;
sort(A, p, q);
combine(A, p, q, r);
}
}
private static void combine(int[] A, int p, int q, int r) {
int i = q - p;
int val = A[r];
while (i >= 0 && val < A[p + i]) {
A[p + i + 1] = A[p + i];
A[p + i] = val;
i--;
}
}
public static void main(String... strings) {
int[] A = { 2, 5, 3, 1, 7 };
sort(A, 0, A.length - 1);
Arrays.stream(A).sequential().forEach(i -> System.out.print(i + ", "));
}
public class test
{
public static void main(String[] args){
test h = new test();
int a[] = { 5, 8, 9, 13, 65, 74, 25, 44, 67, 2, 1 };
h.ins_rec(a, a.length-1);
for(int i=0; i<a.length; i++)
log(a[i]);
}
void ins_rec(int a[], int j){
if( j == 0 ) return;
ins_rec(a, j - 1);
int key = a[ j ];
sort(a, key, j - 1);
}
void sort(int a[], int key, int i){
if( (i < 0) || (a[i] < key) ) {
a[ i + 1 ] = key;
return;
}
a[ i + 1 ] = a[ i ];
sort(a, key, i - 1);
}
private static void log(int aMessage){
System.out.println("\t\t"+aMessage);
}
}

Categories