I've been working on this three way merge sort algorithm which I based off of my normal merge sort code; however, it isn't sorting correctly and so I believe there might be a minor mistake in my code. Any help please? I've been looking into the code for 3 hours trying to find the problem but it has proven difficult.
public class TriMergeSort {
void merge(int arr[], int low, int mid1, int mid2, int high) {
int sizeA = mid1 - low + 1;
int sizeB = mid2 - mid1;
int sizeC = high - mid2;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
int C[] = new int[sizeC];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid1 + j + 1];
for (int x = 0; x < sizeC; x++)
C[x] = arr[mid2 + x + 1];
int i = 0, j = 0, x = 0;
int k = low;
while (i < sizeA && j < sizeB && x < sizeC) {
if (A[i] < B[j] && A[i] < C[x]) {
arr[k] = A[i];
i++;
} else
if (A[i] >= B[j] && B[j] < C[x]) {
arr[k] = B[j];
j++;
} else
if (A[i] > C[x] && B[j] >= C[x]) {
arr[k] = C[x];
x++;
}
k++;
}
while (i < sizeA) {
arr[k] = A[i];
i++;
k++;
}
while (j < sizeB) {
arr[k] = B[j];
j++;
k++;
}
while (x < sizeC) {
arr[k] = C[x];
x++;
k++;
}
}
void sort(int arr[], int low, int high) {
if (low < high) {
int mid1 = low + ((high - low) / 3);
int mid2 = low + 2 * ((high - low) / 3) + 1;
sort(arr, low, mid1);
sort(arr, mid1 + 1, mid2);
sort(arr, mid2 + 1, high);
merge(arr, low, mid1, mid2, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12 };
TriMergeSort test = new TriMergeSort();
test.sort(arr, 0, arr.length - 1);
print(arr);
}
}
The code posted in the question works fine. You did not post the 3-way merge code you have problems with.
Note that instead of passing high as the index to the last item in the slice to sort, you should pass the index of the first element beyond the slice. This allows for simpler code, without confusing and error prone +1/-1 adjustments.
Here is a modified version:
public class MergeSort {
void merge(int arr[], int low, int mid, int high) {
int sizeA = mid - low;
int sizeB = high - mid;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid + j];
int i = 0, j = 0;
int k = low;
while (i < sizeA && j < sizeB) {
if (A[i] <= B[j]) {
arr[k++] = A[i++];
} else {
arr[k++] = B[j++];
}
}
while (i < sizeA) {
arr[k++] = A[i++];
}
while (j < sizeB) {
arr[k++] = B[j++];
}
}
void sort(int arr[], int low, int high) {
if (high - low >= 2) {
int mid = low + (high - low) / 2;
sort(arr, low, mid);
sort(arr, mid, high);
merge(arr, low, mid, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12, 10, 59 };
MergeSort test = new MergeSort();
test.sort(arr, 0, arr.length);
print(arr);
}
}
To convert this into a 3-way merge version, sort3 must follow these steps:
split the range into 3 slices instead of 2. The first slice runs from low to mid1 = low + (high - low)/3 excluded, the second from mid1 to mid2 = low + (high - low)*2/3 excluded and the third from mid2 to high excluded.
sort each of the 3 subslices recursively
call merge3(arr, low, mid1, mid2, high)
make copies of the 3 subslices
write a loop for 3 index values running the 3 slices until one of them is exhausted
write 3 loops for the 2 remaining slices (A and B) or (B and C) or (A and C),
write 3 loops to copy the remaining elements from the remaining slice, A, B or C
EDIT: the merge function in your TriMergeSort class is missing the 3 loops that merge 2 slices once one of the 3 initial slices is exhausted. This explains why the array does not get properly sorted. After the 3-way merge loop, you should have:
while (i < sizeA && j < sizeB) {
...
}
while (i < sizeA && x < sizeC) {
...
}
while (j < sizeB && x < sizeC) {
...
}
To avoid all these repeated loops, you could combine tests on the index values into a single loop body:
public class TriMergeSort {
void merge(int arr[], int low, int mid1, int mid2, int high) {
int sizeA = mid1 - low;
int sizeB = mid2 - mid1;
int sizeC = high - mid2;
int A[] = new int[sizeA];
int B[] = new int[sizeB];
int C[] = new int[sizeC];
for (int i = 0; i < sizeA; i++)
A[i] = arr[low + i];
for (int j = 0; j < sizeB; j++)
B[j] = arr[mid1 + j];
for (int k = 0; k < sizeC; k++)
C[k] = arr[mid2 + k];
int i = 0, j = 0, k = 0;
while (low < high) {
if (i < sizeA && (j >= sizeB || A[i] <= B[j])) {
if (k >= sizeC || A[i] <= C[k]) {
arr[low++] = A[i++];
} else {
arr[low++] = C[k++];
}
} else {
if (j < sizeB && (k >= sizeC || B[j] <= C[k])) {
arr[low++] = B[j++];
} else {
arr[low++] = C[k++];
}
}
}
}
void sort(int arr[], int low, int high) {
if (high - low >= 2) {
int mid1 = low + (high - low) / 3;
int mid2 = low + (high - low) * 2 / 3;
sort(arr, low, mid1);
sort(arr, mid1, mid2);
sort(arr, mid2, high);
merge(arr, low, mid1, mid2, high);
}
}
static void print(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String args[]) {
int arr[] = { 15, 2, 6, 7, 55, 0, 28, 41, 12 };
TriMergeSort test = new TriMergeSort();
test.sort(arr, 0, arr.length);
print(arr);
}
}
The while loop above can be further simplified but somewhat less readable as:
while (low < high) {
if (i < sizeA && (j >= sizeB || A[i] <= B[j])) {
arr[low++] = (k >= sizeC || A[i] <= C[k]) ? A[i++] : C[k++];
} else {
arr[low++] = (j < sizeB && (k >= sizeC || B[j] <= C[k])) ? B[j++] : C[k++];
}
}
And even one step further:
while (low < high) {
arr[low++] = (i < sizeA && (j >= sizeB || A[i] <= B[j])) ?
((k >= sizeC || A[i] <= C[k]) ? A[i++] : C[k++]) :
(j < sizeB && (k >= sizeC || B[j] <= C[k])) ? B[j++] : C[k++];
}
I am trying to find out the number of inversion in any array. I have applied mergesort. And when merging the sub arrays I counted the number if any value of right subarray is less than any value of left sub array. This code does not work if the array contains a lot of data.
private static long getNumberOfInversions(int[] a, int[] b, int left,
int right)
{
long numberOfInversions = 0;
if (right > left)
{
int ave = (left + right) / 2;
numberOfInversions = getNumberOfInversions(a, b, left, ave);
numberOfInversions += getNumberOfInversions(a, b, ave + 1, right);
numberOfInversions += merge(a, b, left, ave + 1, right);
}
return numberOfInversions;
}
public static long merge(int[] a, int b[], int left, int ave, int rigth)
{
int i = 0, j = left, k = ave;
long count = 0;
while (j <= ave - 1 && k <= rigth)
{
if (a[j] <= a[k])
{
b[i] = a[j];
i++;
j++;
}
else
{
b[i] = a[k];
count += ave - j;
i++;
k++;
}
}
while (j <= ave - 1)
{
b[i] = a[j];
i++;
j++;
}
while (k <= rigth)
{
b[i] = a[k];
i++;
k++;
}
while (left <= rigth)
{
a[left] = b[i];
left++;
i++;
}
return count;
}
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] a = new int[n];
for (int i = 0; i < n; i++)
{
a[i] = scanner.nextInt();
}
int[] b = new int[n];
System.out.println(getNumberOfInversions(a, b, 0, n - 1));
}
So I'm writing a program that compares Bubble, Selection, Merge, and Quick Sort. All 4 methods are given a randomized array of 1000 elements and I count to see how many times it takes a method to perform to fully sort the array. My question revolves around the placement of my counts. I know I should look at the Big O complexities for each to get a ballpark estimate of the number but I'm just asking if I put the counts in the right spots.
Bubble Sort:
public static int[] bubbleSort(int[] a)
{
boolean done = false;
int n = a.length;
while(done == false)//runs n times
{
done = true;
for(int i = 0; i < n-1; i++)//runs n times
{
if(a[i] > a[i+1])//Swap
{
bubbleCount++;
int temp = a[i];
a[i] = a[i+1];
a[i+1] = temp;
done = false;
}
}
}
return a;
}
Selection Sort:
public static void selectionSort(int[] a )
{
for (int i = 0; i < a.length - 1; i++)
{
int pos = i;
for (int j = i + 1; j < a.length; j++)
{
// increments selection count
selectionCount++;
// if a[j] is less than a[pos], set pos to j
if (a[j] < a[pos])
{
pos = j;
}
}
// swaps a[i] and a[pos]
int temp = a[i];
a[i] = a[pos];
a[pos] = temp;
}
}
Merge Sort:
public static void mergeSort(int [] a)
{
//put counter for checks inside method
int size = a.length;
if(size < 2)//Halt recursion
{
return;
}
int mid = size/ 2;
int leftSize = mid;
int rightSize = size - mid;
int[] left = new int[leftSize];
int[] right = new int[rightSize];
//populate left
for(int i = 0; i < mid; i++)
{
mergeCount++;
left[i] = a[i];
}
//populate right
for(int i = mid; i < size; i++)
{
mergeCount++;
right[i-mid] = a[i];
}
mergeSort(left);
mergeSort(right);
//merge
merge(left, right, a);
}
public static void merge(int[] left, int[] right, int[] a)
{
int leftSize = left.length;
int rightSize = right.length;
int i = 0;//index for left
int j = 0;//index for right
int k = 0;//index for a
while(i < leftSize && j < rightSize)//compares until the end is reach in either
{
if(left[i] <= right[j])
{
//assigns a[k] to left[i] and increments both i and k
a[k] = left[i];
i++;
k++;
}
else
{
//assigns a[k] to right [j] and increments j and k
a[k] = right[j];
j++;
k++;
}
}
//fills in the rest
while(i<leftSize)
{
a[k] = left[i];
i++;
k++;
}
while(j<rightSize)
{
a[k] = right[j];
j++;
k++;
}
}
Quick Sort
public static void quickSort(int[] a, int left, int right)
{
int index = partition(a, left, right);
if(left < index - 1)
{
//increments quickCount and calls quickSort recursively
quickCount++;
quickSort(a, left, index-1);
}
if(index < right)
{
//increments quickCount and calls quicSort recursively
quickCount++;
quickSort(a, index, right);
}
}
public static int partition(int[] a, int left, int right)
{
int i = left;
int j = right;
int pivot = a[((left+right)/2)];
while(i<=j)
{
while(a[i] < pivot)
{
i++;//correct position so move forward
}
while(a[j] > pivot)
{
j--;//correct position
}
if(i <= j)
{
//swaps and increments i and decrements j
int temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
return i;
}
Your counts should be wherever you do a comparison of two values.
The bubbleCount should be moved up above the if because you want to count every comparison not sure the ones where the if clause is true. The selectionCount seems okay. The mergeCount should be moved to where you compare values.
You need to count comparisons, so I would create a method to compare and count:
static int count;
private static boolean isGreaterThan(int i, int j) {
count++;
return i > j;
}
and always use that method to compare values:
instead of:
while(i<=j)
do:
while(!isGreaterThan(i, j))
etc
This is a problem for an Algorithms course I'm taking that I can't figure out.
// modify the array x to generate the next k-combination from x.
// In general, the first k-combination of n elements is { 1, 2, ..., k }
// and the last k-combination is { n-k+1, n-k+2, ..., n }.
public static boolean nextCombination (int x[], int k, int n) {
for (int j = k-1; j >= 0; j--)
if (x[j] <= (n - k + j)) {
x[j]++;
for (int i = 1; i < k - j; i++)
x[i+j] = x[j]+i;
return true;
}
return false;
}
It gets called by this method:
// print all k-combinations of n elements.
public static void enumerateCombinations (int k, int n) {
int x[] = new int[100]; // k <= 100
System.out.println("All " + k + "-combinations of " + n + " numbers:");
for (int j = 0; j < k; j++)
x[j] = j+1;
while (true) {
printArray(x, k);
if (nextCombination(x, k, n) == false)
break;
}
}
Any help would be appreciated.
With this code you transform the nextCombination method into a recursive one.
public static boolean nextCombinationRecursive (int j, int x[], int k, int n) {
if (j < 0 || j > k) return false;
if (x[j] <= (n - k + j)) {
x[j]++;
for (int i = 1; i < k - j; i++)
x[i+j] = x[j]+i;
return true;
}
return nextCombinationRecursive(j - 1, x, k, n);
}
And you call it from enumerateCombinations like this:
if (nextCombinationRecursive(k - 1, x, k, n) == false)
I am new to Java and have tried to implement mergesort in Java. However, even after running the program several times, instead of the desired sorted output, I am getting the same user given input as the output. I would be thankful if someone could help me understand this unexpected behaviour.
import java.io.*;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) throws IOException {
BufferedReader R = new BufferedReader(new InputStreamReader(System.in));
int arraySize = Integer.parseInt(R.readLine());
int[] inputArray = new int[arraySize];
for (int i = 0; i < arraySize; i++) {
inputArray[i] = Integer.parseInt(R.readLine());
}
mergeSort(inputArray);
for (int j = 0; j < inputArray.length; j++) {
System.out.println(inputArray[j]);
}
}
static void mergeSort(int[] A) {
if (A.length > 1) {
int q = A.length / 2;
int[] leftArray = Arrays.copyOfRange(A, 0, q);
int[] rightArray = Arrays.copyOfRange(A, q + 1, A.length);
mergeSort(leftArray);
mergeSort(rightArray);
A = merge(leftArray, rightArray);
}
}
static int[] merge(int[] l, int[] r) {
int totElem = l.length + r.length;
int[] a = new int[totElem];
int i, li, ri;
i = li = ri = 0;
while (i < totElem) {
if ((li < l.length) && (ri < r.length)) {
if (l[li] < r[ri]) {
a[i] = l[li];
i++;
li++;
} else {
a[i] = r[ri];
i++;
ri++;
}
} else {
if (li >= l.length) {
while (ri < r.length) {
a[i] = r[ri];
i++;
ri++;
}
}
if (ri >= r.length) {
while (li < l.length) {
a[i] = l[li];
li++;
i++;
}
}
}
}
return a;
}
}
Here is a corrected version of your code:
import java.io.*;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) throws IOException{
BufferedReader R = new BufferedReader(new InputStreamReader(System.in));
int arraySize = Integer.parseInt(R.readLine());
int[] inputArray = new int[arraySize];
for (int i = 0; i < arraySize; i++) {
inputArray[i] = Integer.parseInt(R.readLine());
}
mergeSort(inputArray);
for (int j = 0; j < inputArray.length; j++) {
System.out.println(inputArray[j]);
}
}
static void mergeSort(int[] A) {
if (A.length > 1) {
int q = A.length/2;
//changed range of leftArray from 0-to-q to 0-to-(q-1)
int[] leftArray = Arrays.copyOfRange(A, 0, q-1);
//changed range of rightArray from q-to-A.length to q-to-(A.length-1)
int[] rightArray = Arrays.copyOfRange(A,q,A.length-1);
mergeSort(leftArray);
mergeSort(rightArray);
merge(A,leftArray,rightArray);
}
}
static void merge(int[] a, int[] l, int[] r) {
int totElem = l.length + r.length;
//int[] a = new int[totElem];
int i,li,ri;
i = li = ri = 0;
while ( i < totElem) {
if ((li < l.length) && (ri<r.length)) {
if (l[li] < r[ri]) {
a[i] = l[li];
i++;
li++;
}
else {
a[i] = r[ri];
i++;
ri++;
}
}
else {
if (li >= l.length) {
while (ri < r.length) {
a[i] = r[ri];
i++;
ri++;
}
}
if (ri >= r.length) {
while (li < l.length) {
a[i] = l[li];
li++;
i++;
}
}
}
}
//return a;
}
}
When you rebind A in mergeSort():
A = merge(leftArray,rightArray);
this has no effect in inputArray in main().
You need to return the sorted array from mergeSort() similarly to how you return it from merge().
static int[] mergeSort(int[] A) {
...
return A;
}
and in main():
int[] mergedArray = mergeSort(inputArray);
for (int j = 0; j < mergedArray.length; j++) {
System.out.println(mergedArray[j]);
}
The problem is that java is pass by value and not pass by reference... When you are assigning to array A in the merge method you are changing a copy of the reference to A and not the reference to A itself. Therefore you need to pass A into your merge method and make a structural change to A.
The problem lies here:
A = merge(leftArray,rightArray);
Now your merge array does this:
static int[] merge(int[] l, int[] r) {
int[] a = new int[totElem];
// bunch of code
return a;
}
When you started, A was a reference to inputArray. But then you reassigned it to be whatever came out of merge. Unfortunately, that doesn't touch what inputArray is in the main method. That basically says "Oh look at all the work you did... throw it away!"
You could change that with something like
static int[] mergeSort(int[] A) {
// A = merge... // not this
return merge... // use this
}
Then in your main method, you can do
int[] merged = mergeSort(inputArray);
for(int i : merged) System.out.println(i);
public class MergeSort{
public static void sort(int[] in){
if(in.length <2) return; //do not need to sort
int mid = in.length/2;
int left[] = new int[mid];
int right[] = new int[in.length-mid];
for(int i=0; i<mid; i++){ //copy left
left[i] = in[i];
}
for(int i=0; i<in.length-mid; i++){ //copy right
right[i] = in[mid+i];
}
sort(left);
sort(right);
merge(left, right, in);
}
private static void merge(int[] a, int[] b, int[] all){
int i=0, j=0, k=0;
while(i<a.length && j<b.length){ //merge back
if(a[i] < b[j]){
all[k] = a[i];
i++;
}else{
all[k] = b[j];
j++;
}
k++;
}
while(i<a.length){ //left remaining
all[k++] = a[i++];
}
while(j<b.length){ //right remaining
all[k++] = b[j++];
}
}
public static void main(String[] args){
int[] a = {2,3,6,4,9,22,12,1};
sort(a);
for(int j=0; j<a.length; j++){
System.out.print(a[j] + " ");
}
}
}
public void sort(int[] randomNumbersArrray)
{
copy = randomNumbersArrray.clone();
mergeSort(0 , copy.length - 1);
}
private void mergeSort(int low, int high)
{
if(low < high)
{
int mid = ((low + high) / 2);
mergeSort(low, mid); //left side
mergeSort(mid + 1, high); // right side
merge(low, mid, high); //combine them
}
}
private void merge(int low, int mid, int high)
{
int temp[] = new int[high - low + 1];
int left = low;
int right = mid + 1;
int index = 0;
// compare each item for equality
while(left <= mid && right <= high)
{
if(copy[left] < copy[right])
{
temp[index] = copy[left];
left++;
}else
{
temp[index] = copy[right];
right++;
}
index++;
}
// if there is any remaining loop through them
while(left <= mid || right <= high)
{
if( left <= mid)
{
temp[index] = copy[left];
left++;
index++;
}else if(right <= high)
{
temp[index] = copy[right];
right++;
index++;
}
}
// copy back to array
for(int i = 0; i < temp.length; i++)
{
copy[low + i] = temp[i];
}
}
package Sorting;
public class MergeSort {
private int[] original;
private int len;
public MergeSort(int length){
len = length;
original = new int[len];
original[0]=10;
original[1]=9;
original[2]=8;
original[3]=7;
original[4]=6;
original[5]=5;
original[6]=4;
original[7]=3;
original[8]=2;
original[9]=1;
int[] aux = new int[len];
for(int i=0;i<len;++i){
aux[i]=original[i];
}
Sort(aux,0,len);
}
public void Sort(int[] aux,int start, int end){
int mid = start + (end-start)/2;
if(start < end){
Sort(aux, start, mid-1);
Sort(aux, mid, end);
Merge(aux, start, mid, end);
}
}
public void Merge(int[] aux, int start, int mid, int end){// while array passing be careful of shallow and deep copying
for(int i=start; i<=end; ++i)
auxilary[i] = original[i];
int i = start;
int k = start;
int j = mid+1;
while(i < mid && j <end){
if(aux[i] < aux[j]){
original[k++] = aux[i++];
}
else{
original[k++] = aux[j++];
}
}
if(i == mid){
while(j < end){
original[k++] = aux[j++];
}
}
if(j == end){
while(i < mid){
original[k++] = aux[i++];
}
}
}
public void disp(){
for(int i=0;i<len;++i)
System.out.print(original[i]+" ");
}
public static void main(String[] args) {
MergeSort ms = new MergeSort(10);
ms.disp();
}
}
The above codes are a little confused
Never use variables with names: "k", "j", "m",... this makes the code very confusing
Follows the code in an easier way...
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
Integer[] itens = {2,6,4,9,1,3,8,7,0};
Integer[] tmp = new Integer[itens.length];
int left = 0;
int right = itens.length - 1;
mergeSort(itens, tmp, left, right);
System.out.println(Arrays.toString(itens));
}
private static void mergeSort(Integer[] itens, Integer[] tmpArray, int left, int right) {
if(itens == null || itens.length == 0 || left >= right){
return;
}
int midle = (left + right) / 2;
mergeSort(itens, tmpArray, left, midle);
mergeSort(itens, tmpArray, midle + 1, right);
merge(itens, tmpArray, left, midle + 1, right);
}
private static void merge(Integer[] itens, Integer[] tmpArray, int left, int right, int rightEnd) {
int leftEnd = right - 1;
int tmpIndex = left;
while (left <= leftEnd && right <= rightEnd){
if (itens[left] < itens[right] ){
tmpArray[tmpIndex++] = itens[left++];
} else {
tmpArray[tmpIndex++] = itens[right++];
}
}
while (left <= leftEnd) { // Copy rest of LEFT half
tmpArray[tmpIndex++] = itens[left++];
}
while (right <= rightEnd) { // Copy rest of RIGHT half
tmpArray[tmpIndex++] = itens[right++];
}
while(rightEnd >= 0){ // Copy TEMP back
itens[rightEnd] = tmpArray[rightEnd--];
}
}
}
Might as well add my take on this:
Takes two int arrays and merges them.
Where 'result' is an array of size a.length + b.length
public static void merge( int[] a, int[] b, int[] result )
{
int i = 0, j = 0;
while ( true )
{
if ( i == a.length )
{
if ( j == b.length )
return;
result[ i + j ] = b[ j ];
j++;
}
else if ( j == b.length )
{
result[ i + j ] = a[ i ];
i++;
}
else if ( a[ i ] < b[ j ] )
{
result[ i + j ] = a[ i ];
i++;
}
else
{
result[ i + j ] = b[ j ];
j++;
}
}
}
public class MyMergeSort {
private int[] array;
private int[] tempMergArr;
private int length;
public static void main(String a[]){
int[] inputArr = {45,23,11,89,77,98,4,28,65,43};
MyMergeSort mms = new MyMergeSort();
mms.sort(inputArr);
for(int i:inputArr){
System.out.print(i);
System.out.print(" ");
}
}
public void sort(int inputArr[]) {
this.array = inputArr;
this.length = inputArr.length;
this.tempMergArr = new int[length];
doMergeSort(0, length - 1);
}
private void doMergeSort(int lowerIndex, int higherIndex) {
if (lowerIndex < higherIndex) {
int middle = lowerIndex + (higherIndex - lowerIndex) / 2;
// Below step sorts the left side of the array
doMergeSort(lowerIndex, middle);
// Below step sorts the right side of the array
doMergeSort(middle + 1, higherIndex);
// Now merge both sides
mergeParts(lowerIndex, middle, higherIndex);
}
}
private void mergeParts(int lowerIndex, int middle, int higherIndex) {
for (int i = lowerIndex; i <= higherIndex; i++) {
tempMergArr[i] = array[i];
}
int i = lowerIndex;
int j = middle + 1;
int k = lowerIndex;
while (i <= middle && j <= higherIndex) {
if (tempMergArr[i] <= tempMergArr[j]) {
array[k] = tempMergArr[i];
i++;
} else {
array[k] = tempMergArr[j];
j++;
}
k++;
}
while (i <= middle) {
array[k] = tempMergArr[i];
k++;
i++;
}
}
}
very simple and easy to understand
static void sort(char[] data) {
int length = data.length;
if (length < 2)
return;
int mid = length / 2;
char[] left = new char[mid];
char[] right = new char[length - mid];
for(int i=0;i<mid;i++) {
left[i]=data[i];
}
for(int i=0,j=mid;j<length;i++,j++) {
right[i]=data[j];
}
sort(left);
sort(right);
merge(left, right, data);
}
static void merge(char[] left, char[] right, char[] og) {
int i = 0, j = 0, k = 0;
while(i < left.length && j < right.length) {
if (left[i] < right[j]) {
og[k++] = left[i++];
} else {
og[k++] = right[j++];
}
}
while (i < left.length) {
og[k++] = left[i++];
}
while (j < right.length) {
og[k++] = right[j++];
}
}
I have a parallel version of Merge Sort. I am benefiting from the RecursiveAction and ForkJoinPool. Note that the number of workers can be set as a constant. However, I am setting it as the number of available processors on the machine.
import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
public class ParallelMergeSorter {
private int[] array;
public ParallelMergeSorter(int[] array) {
this.array = array;
}
public int[] sort() {
int numWorkers = Runtime.getRuntime().availableProcessors(); // Get number of available processors
ForkJoinPool pool = new ForkJoinPool(numWorkers);
pool.invoke(new ParallelWorker(0, array.length - 1));
return array;
}
private class ParallelWorker extends RecursiveAction {
private int left, right;
public ParallelWorker(int left, int right) {
this.left = left;
this.right = right;
}
protected void compute() {
if (left < right) {
int mid = (left + right) / 2;
ParallelWorker leftWorker = new ParallelWorker(left, mid);
ParallelWorker rightWorker = new ParallelWorker(mid + 1, right);
invokeAll(leftWorker, rightWorker);
merge(left, mid, right);
}
}
private void merge(int left, int mid, int right) {
int[] leftTempArray = Arrays.copyOfRange(array, left, mid + 1);
int[] rightTempArray = Arrays.copyOfRange(array, mid + 1, right + 1);
int leftTempIndex = 0, rightTempIndex = 0, mergeIndex = left;
while (leftTempIndex < mid - left + 1 || rightTempIndex < right - mid) {
if (leftTempIndex < mid - left + 1 && rightTempIndex < right - mid) {
if (leftTempArray[leftTempIndex] <= rightTempArray[rightTempIndex]) {
array[mergeIndex] = leftTempArray[leftTempIndex];
leftTempIndex++;
} else {
array[mergeIndex] = rightTempArray[rightTempIndex];
rightTempIndex++;
}
} else if (leftTempIndex < mid - left + 1) {
array[mergeIndex] = leftTempArray[leftTempIndex];
leftTempIndex++;
} else if (rightTempIndex < right - mid) {
array[mergeIndex] = rightTempArray[rightTempIndex];
rightTempIndex++;
}
mergeIndex++;
}
}
}
}
public class MergeTwoSortedArray {
public void approach_2(int[] arr1, int[] arr2) {
List<Integer> result = IntStream.concat(Arrays.stream(arr1), Arrays.stream(arr2)).boxed().sorted()
.collect(Collectors.toList());
System.out.println(result);
}
public void approach_3(Integer[] arr1, Integer[] arr2) {
List<Integer> al1 = Arrays.asList(arr1);
List<Integer> al2 = Arrays.asList(arr2);
List<Integer> result = new ArrayList<>();
int i = 0, j = 0;
while (i < al1.size() && j < al2.size()) {
if (al1.get(i) < al2.get(j)) {
result.add(al1.get(i));
i++;
} else {
result.add(al2.get(j));
j++;
}
}
while (i < al1.size()) {
result.add(al1.get(i));
i++;
}
while (j < al2.size()) {
result.add(al2.get(j));
j++;
}
System.out.println(result);
}
public static void main(String[] args) {
MergeTwoSortedArray obj = new MergeTwoSortedArray();
int[] arr1 = { 3, 6, 76, 85, 91 };
int[] arr2 = { 1, 6, 78, 89, 95, 112 };
obj.approach_2(arr1, arr2);
Integer[] arr3 = { 3, 6, 76, 85, 91 };
Integer[] arr4 = { 1, 6, 78, 89, 95, 112 };
obj.approach_3(arr3, arr4);
}
}