Another variant of merge sort - java

I was supposed to come with a more efficient variant of merge sort that avoids recursive allocation of arrays while using two mutually recursive methods. However, this one is not becoming a more efficient one since its running time slower than the usual one. Any advice would be appreciated
public static void main(String[] args) {
int[] array = {38, 27, 43, 3, 9, 82};
System.out.println("begin with: \n" + Arrays.toString(array));
System.out.println("------------------");
mergesort1(array, array.length);
System.out.println("------------------");
System.out.println("end with: \n" + Arrays.toString(array));
}
public static void mergesort1(int[] a, int last) {
if (last > 1) {
int l = (last / 2);
int r = last - l;
int[] leftArray = new int[l];
int[] rightArray = new int[r];
for (int i = 0; i < l; i++) {
leftArray[i] = a[i];
}
for (int i = l; i < l + r; i++) {
rightArray[i - l] = a[i];
}
mergesort1(rightArray, r);
System.arraycopy(rightArray, 0, a, l, r);
int[] t = new int[l];
mergesort2(leftArray, l, t);
System.arraycopy(t, 0, a, 0, l);
merge(t, l, last, a);
t = null;
}
}
public static void mergesort2(int[] b, int last, int[] d) {
if (last > 1) {
int l = (last / 2);
int r = last - l;
int[] leftArray = new int[l];
int[] rightArray = new int[r];
int[] dArray = new int[r];
System.arraycopy(b, 0, leftArray, 0, l);
System.arraycopy(b, l, rightArray, 0, r);
System.arraycopy(d, l, dArray, 0, r);
mergesort1(leftArray, l);
System.arraycopy(leftArray, 0, b, 0, l);
mergesort2(rightArray, r, dArray);
System.arraycopy(rightArray, 0, b, l, r);
System.arraycopy(dArray, 0, d, l, r);
merge(b, l, last, d);
} else {
d[0] = b[0]; // Trivial case
}
}
public static void merge(int[] le, int l, int n, int[] a) {
int i = 0;
int j = l;
int k = 0;
int myTemp = 0;
while ((i < l)) {
if ((le[i] <= a[j]) || (a[j] == 0)) {
if ((k < a.length)) {
a[k] = le[i];
i++;
}
} else {
if ((k < a.length)) {
int innerTemp = 0;
if (myTemp == 0) {
a[k] = a[j];
innerTemp = 1;
}
j++;
if (j == n) {
j--;
myTemp = 1;
if (innerTemp == 0) {
a[k] = le[i];
i++;
}
}
}
}
if ((k < a.length)) {
k++;
}
}
}
*Updated
I have to tried to update the code according to the suggestion below and still it doesn't give out the correct result.
public static void main(String[] args) {
int[] array = {38, 27, 43, 3, 9, 82};
System.out.println("begin with: \n" + Arrays.toString(array));
System.out.println("------------------");
mergesort(array, array.length);
System.out.println("------------------");
System.out.println("end with: \n" + Arrays.toString(array));
}
public static void mergesort(int[] a, int size) {
if (size < 2) {
return;
}
int[] b = new int[size];
mergesort1(a, b, 0, size-1);
}
public static void mergesort1(int[] a, int[] b, int low, int end) {
if ((end - low) == 1)
{
return;
}
int mid = (low + end) / 2;
mergesort1(a, b, low, mid);
mergesort2(a, b, mid, end);
merge(b, a, low, mid, end);
}
public static void mergesort2(int[] a, int[] b, int low, int end) {
if ((end - low) == 1) {
b[low] = a[low];
return;
}
int mid = (low + end) / 2;
mergesort1(a, b, low, mid);
mergesort2(a, b, mid, end);
merge(a, b, low, mid, end);
}
public static void mergeArrays(int[] toSort, int[] tempArray, int low, int mid, int high) {
int i = 0;
int j = mid;
int k = 0;
int myTemp = 0;
while ((i < mid)) {
if ((tempArray[i] <= toSort[j]) || (toSort[j] == 0)) {
if ((k < toSort.length)) {
toSort[k] = tempArray[i];
i++;
}
} else {
if ((k < toSort.length)) {
int innerTemp = 0;
if (myTemp == 0) {
toSort[k] = toSort[j];
innerTemp = 1;
}
j++;
if (j == high) {
j--;
myTemp = 1;
if (innerTemp == 0) {
toSort[k] = tempArray[i];
i++;
}
}
}
}
if ((k < toSort.length)) {
k++;
}
}
}

You are using lots of unnecessary System.arraycopy. You only have to use array copy once after the merge, to copy the merged array into the original array. And for passing your sub-arrays to the inner functions you just have to pass the start and end indices of the sub-arrays. There is no need to copy them into another array and pass those to the functions.

In order to avoid recursive allocation, do a one time allocation of the temp buffer, either in main() or in an entry function that calls one of the mutually recursive functions. The mutually recursive functions just generate indices and eliminate the need to copy back, while merge() does the actual merging. This partial example uses half closed intervals, first (low) and end for parameters.
void mergesort(int[] a, int size){ // entry function
if(size < 2)
return;
int[] b = new int[size]; // allocate temp buffer just once
mergesortatoa(a, b, 0, size); // sort a
delete[] b; // delete b
}
// merge sort from a to a
void mergesortatoa(int[] a, int[] b, int low, int end)
{
if((end - low) == 1) // if just 1 element
return; // return
int mid = (low + end)/2 // or low + (end - low)/2
mergesortatob(a, b, low, mid);
mergesortatob(a, b, mid, end);
merge(b, a, low, mid, end);
}
// merge sort from a to b
void mergesortatob(int[] a, int[] b, int low, int end)
{
if((end - low) == 1){ // if just 1 element
b[low] = a[low]; // "mergesort" a to b
return; // return
}
int mid = (low + end)/2 // or low + (end - low)/2
mergesortatoa(a, b, low, mid);
mergesortatoa(a, b, mid, end);
merge(a, b, low, mid, end);
}
// merge from x to y (no copy, just y[...] = x[...])
void merge(int[] x, int[] y, int low, int mid, int end)
{
// ...
}

You can avoid many copies by allocating a single array of the same size as the original and perform the merges alternatively to the other array.
When you get to tiny subarrays, the parity of the recursion depth will tell you if you need to merge in-place or to the other array.
38, 27, 43, 3, 9, 82
- - - - - -
====================== (in-place 0-1 and 3-4)
27, 38, 43, 3, 9, 82
- - - - - -
====================== (to copy, 0-2 and 3-5)
- - - - - -
27, 38, 43, 3, 9, 82
====================== (to original, 0-5)
3, 9, 27, 38, 43, 82
- - - - - -

Related

Why does this QuickSort code fail using Hoare's partition?

class QuickSort {
public static void main(String[] args) {
int arr[] = { 8, 3, 5, 1, 34, 6, 35, 5, 23, 2, 7 };
int n = arr.length;
for (int x : arr)
System.out.print(x + " ");
System.out.println();
qSort(arr, 0, n - 1);
for (int x : arr)
System.out.print(x + " ");
}
static int partition(int arr[], int l, int h) {
int pivot = arr[h];
int i = l - 1, j = h + 1;
while (true) {
do {
i++;
} while (arr[i] < pivot);
do {
j--;
} while (arr[j] > pivot);
if (i >= j)
return j;
swap(i,j,arr);
}
}
static void qSort(int arr[], int l, int h) {
if (l < h) {
int p = partition(arr, l, h);
qSort(arr, l, p);
qSort(arr, p + 1, h);
}
}}
It works when I choose the pivot as arr[l] , however gives stackoverflow error because if recursion when pivot is chosen as arr[h].
Does the choice of pivot matter? And if at all it matters, could you please tell why?
Hoare partition scheme will not work if arr[h] is chosen as the pivot. It will work for any other element of arr[l] to arr[h-1]. The failure occurs when the size is reduced to 2 elements, h = l+1, and a[l] < a[h]. The loop exits with i == h and j == h, and returns h. Then it calls itself again, with the same values for l and h (h == l+1), resulting in infinite recursion stopped only by a stack overflow exception.
Typcially for Hoare partition scheme arr[(l+h)/2] is chosen as the pivot. This relies on the divide by 2 to round down to l when h = l+1.

Merge sort auxiliary array creation/ middle question

I have some questions about my code. I've marked it with ---><--- down below.
public class Main {
public static void main(String[] args) {
int[] arr = {5, 4, 3, 2, 1, 4, 5, 6, 7, 8, 10};
int[] aux = new int[arr.length];
sort(arr, aux, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
public static void sort(int[] arr, int[] aux, int low, int high) {
// what does these lines do? --->
if (low >= high) {
return;
}
int mid = low + (high - low) / 2; // why cant it just be high - low / 2
//<--- These lines
sort(arr, aux, low, mid); //sorts left side
sort(arr, aux, mid + 1, high); //sorts right side
merge(arr, aux, low, mid, high); //merges the two sides
}
public static void merge(int[] arr, int[] aux, int low, int mid, int high) {
for (int k = low; k <= high; k++) {
aux[k] = arr[k];
}
//copies the array into an aux array
int i = low; //counter for the left side
int j = mid + 1; //counter for the right side
for (int k = low; k <= high; k++) {
if (i > mid) { //if i > mid meaning that if the left side of the array is empty then use the right side
arr[k] = aux[j++];
}
else if (j > high) { //if j > high then right side of array has been used so use left
arr[k] = aux[i++];
}
else if (aux[i] <= aux[j]) { //if value of left side is <= value of right then bring leftside value up to original array
arr[k] = aux[i++];
}
else { //value of right side is <= value of left so bring rightside value up to original array
arr[k] = aux[j++];
}
}
}
}
This is a part of the merge from GeeksForGeeks
void merge(int arr[], int l, int m, int r) {
/* Create temp arrays */
// These lines --->
int L[] = new int [n1];
int R[] = new int [n2];
//<---
}
With G4Geek's temp arrays:
Is it getting created every single time merge is called?
Does the memory just stay there?
Is the current code that I have better practice?
Thanks.

Java divide and conquer algorithm stack overflow error

I am trying to find out the index of the smallest number in an int array using divide and conquer and I have this stack overflow error:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.StrictMath.floor(Unknown Source)
at java.lang.Math.floor(Unknown Source)
This is my divide and conquer method:
private static int dC(int[] a, int f, int l) {
if(f == 1)
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Here is what I put in my main method:
int[] a = {35,30,40,50};
System.out.println(dC(a, 0, 3));
You have a problem with your stoping "rule"
private static int dC(int[] a, int f, int l) {
if(l == f) // <-- This mean you have one item, so you want to return it.
return f;
if(a[dC(a, f, (int)(Math.floor((double)(f+l)/2)))] > a[dC(a, (int)(Math.floor((double)(f+l)/2)+1), l)])
return dC(a, (int)(Math.floor((double)(f+l)/2)+1), l);
else
return dC(a, f, (int)(Math.floor((double)(f+l)/2)));
}
Also, I would try to do the calculation only once, so something like this (also what Joop Eggen said about Integers arithmetics):
private static int dC(int[] a, int f, int l) {
if(l == f)
return f;
int m = (f+l) / 2;
int left = dC(a, f, m);
int right = dC(a, m+1, l);
if(a[left] > a[right])
return left;
else
return right;
}
This is just the classical binary search problem. From what I can glean by looking at your code, you seem to be getting bogged down in the logic used to make each recursive call to the left and right subarrays of the current array. The logic I used below is to take everything from the start to (start+end)/2 for the left recursion, and everything from ((start+end)/2) + 1 to end for the right recursion. This guarantees that there would never be any overlap.
The base case occurs when the algorithm finds itself sitting on a single entry in the array. In this case, we just return that value, and we do not recurse further.
private static int dC(int[] a, int start, int end) {
if (start == end) return a[start];
int left = dC(a, start, (start+end)/2);
int right = dC(a, ((start+end)/2) + 1, end);
return left < right ? left : right;
}
public static void main(String args[])
{
int[] a = {10, 3, 74, 0, 99, 9, 13};
System.out.println(dC(a, 0, 6)); // prints 0
}
Demo
Note: I have no idea what role Math.floor would be playing here, since you're using arrays of integer numbers, not doubles or floats. I removed this, because I saw no need for it.
It's a typical problem locating the index to the min/max, you can try it as:
public static void main(String... args) {
int[] arr = generateArrays(100, 1000, 0, 10000, true);
int minIndex = findMinIndex(arr, 1, arr.length - 1);
int theMin = arr[minIndex];
Arrays.sort(arr);
System.out.println(String.format("The min located correctly: %s", arr[0] == theMin));
}
private static int findMinIndex(int[] a, int l, int r) {
if (r - l < 1) return l;
int mid = l + (r - l) / 2;
int lIndex = findMinIndex(a, l + 1, mid);
int rIndex = findMinIndex(a, mid + 1, r);
int theMinIndex = l;
if (a[lIndex] < a[theMinIndex]) theMinIndex = lIndex;
if (a[rIndex] < a[theMinIndex]) theMinIndex = rIndex;
return theMinIndex;
}
And the helper to generate a random array.
public static int[] generateArrays(int minSize, int maxSize, int low, int high, boolean isUnique) {
Random random = new Random(System.currentTimeMillis());
int N = random.nextInt(maxSize - minSize + 1) + minSize;
if (isUnique) {
Set<Integer> intSet = new HashSet<>();
while (intSet.size() < N) {
intSet.add(random.nextInt(high - low) + low);
}
return intSet.stream().mapToInt(Integer::intValue).toArray();
} else {
int[] arr = new int[N];
for (int i = 0; i < N; ++i) {
arr[i] = random.nextInt(high - low) + low;
}
return arr;
}
}

Recursive Quick Sort in java

This is my quicksort Code. It gives me a wrong answer but i think my partition function is correct.
public class Quick_Sort {
public static void main(String[] args)
{
int a[] = {99,88,5,4,3,2,1,0,12,3,7,9,8,3,4,5,7};
quicksort(a, 0, a.length-1);
}
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
int j = hi-1;
while(i<j)
{
if(a[i]<=a[pivot])
{
i++;
}
if(a[i]>a[pivot])
{
if((a[i]>a[pivot]) && (a[j]<=a[pivot]))
{
int temp= a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
if(a[j]>a[pivot])
{
j--;
}
}
}
int temp= a[i];
a[i]=a[pivot];
a[pivot]=temp;
return i;
}
static void quicksort(int[] a, int low, int hi)
{
if(low>=hi)
{
return;
}
int split = partition(a, low, hi);
quicksort(a, low, split-1);
quicksort(a, split+1, hi);
}
}
This is the final output:
1 0 3 2 3 4 4 5 5 7 3 7 8 9 12 88 99
Tried dry running it, couldn't see the error
In your partition method you have assigned j to hi - 1. It should be set to hi only.
static int partition(int[] a, int low , int hi)
{
int pivot = hi;
int i =low;
// int j = hi-1; // CHANGE THIS TO
int j = hi; // THIS
while(i<j)
I got this output after I made that change:
[0, 1, 2, 3, 3, 3, 4, 4, 5, 5, 7, 7, 8, 9, 12, 88, 99]
Hope this helps!
This is C# code:
public void RecursiveQuickSort(int[] array, int start, int end)
{
if (start < end)
{
int pivot = start;
int left = start + 1;
int right = end;
while (true)
{
while (array[left] <= array[pivot] && left < right)
left++;
while (array[right] > array[pivot] && left < right)
right--;
if (left < right)
{
Swap(array, left, right);
}
else
{
pivot = (array[pivot] > array[left]) ? left : left - 1;
Swap(array, start, pivot);
RecursiveQuickSort(array, start, pivot - 1);
RecursiveQuickSort(array, pivot + 1, end);
return;
}
}
}
}
private void Swap(int[] array, int index1, int index2)
{
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
This is a very good implementation and is much more Java standard. Maybe you want to take a look here, obviously all credits go to the original author.
http://www.vogella.com/tutorials/JavaAlgorithmsQuicksort/article.html
this is how I made it C:
private static List<Integer> recursive_quick_sort (List<Integer> list){
if (list.size()< 2){
return list;
}else {
int pivot = list.get(0);
List<Integer> less = list.stream().filter(element -> element < pivot ).collect(Collectors.toList());
List <Integer> greater = list.stream().filter(element -> element > pivot ).collect(Collectors.toList());
List<Integer> newList = Stream.of(recursive_quick_sort(less),List.of(pivot),recursive_quick_sort(greater))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return newList;
}
}

Merge Sort Java

I am trying to make a merge sort method, but it keeps on giving the wrong sorts. Where do I have change to make it actually sort the array? What part of the code has to be different? Thank you for your time.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
int elements = (rHigh - lHigh +1) ;
int[] temp = new int[elements];
int num = left;
while ((left <= lHigh) && (right <= rHigh)){
if (a[left] <= array[right]) {
temp[num] = array[left];
left++;
}
else {
temp[num] = array[right];
right++;
}
num++;
}
while (left <= right){
temp[num] = array[left]; // I'm getting an exception here, and is it because of the num???
left += 1;
num += 1;
}
while (right <= rHigh) {
temp[num] = array[right];
right += 1;
num += 1;
}
for (int i=0; i < elements; i++){
array[rHigh] = temp[rHigh];
rHigh -= 1;
}
EDIT: now the mergeSort doesn't really sort the numbers, can someone tell me where it specifically is? especially when I print the "Testing merge sort" part.
First of all, I'm assuming this is academic rather than practical, since you're not using a built in sort function. That being said, here's some help to get you moving in the right direction:
Usually, one can think of a merge sort as two different methods: a merge() function that merges two sorted lists into one sorted list, and mergeSort() which recursively breaks the list into single element lists. Since a single element list is sorted already, you then merge all the lists together into one big sorted list.
Here's some off-hand pseudo-code:
merge(A, B):
C = empty list
While A and B are not empty:
If the first element of A is smaller than the first element of B:
Remove first element of A.
Add it to the end of C.
Otherwise:
Remove first element of B.
Add it to the end of C.
If A or B still contains elements, add them to the end of C.
mergeSort(A):
if length of A is 1:
return A
Split A into two lists, L and R.
Q = merge(mergeSort(L), mergeSort(R))
return Q
Maybe that'll help clear up where you want to go.
If not, there's always MergeSort at wikipedia.
Additional:
To help you out, here are some comments inline in your code.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
// what do lHigh and rHigh represent?
int elements = (rHigh - lHigh +1) ;
int[] temp = new int[elements];
int num = left;
// what does this while loop do **conceptually**?
while ((left <= lHigh) && (right <= rHigh)){
if (a[left] <= a[right]) {
// where is 'pos' declared or defined?
temp[pos] = a[left];
// where is leftLow declared or defined? Did you mean 'left' instead?
leftLow ++;
}
else {
temp[num] = a[right];
right ++;
}
num++;
}
// what does this while loop do **conceptually**?
while (left <= right){
// At this point, what is the value of 'num'?
temp[num] = a[left];
left += 1;
num += 1;
}
while (right <= rHigh) {
temp[num] = a[right];
right += 1;
num += 1;
}
// Maybe you meant a[i] = temp[i]?
for (int i=0; i < elements; i++){
// what happens if rHigh is less than elements at this point? Could
// rHigh ever become negative? This would be a runtime error if it did
a[rHigh] = temp[rHigh];
rHigh -= 1;
}
I'm purposefully being vague so you think about the algorithm. Try inserting your own comments into the code. If you can write what is conceptually happening, then you may not need Stack Overflow :)
My thoughts here are that you are not implementing this correctly. This is because it looks like you're only touching the elements of the array only once (or close to only once). This means you have a worst case scenario of O(N) Sorting generally takes at least O(N * log N) and from what I know, the simpler versions of merge sort are actually O(N^2).
More:
In the most simplistic implementation of merge sort, I would expect to see some sort of recursion in the mergeSort() method. This is because merge sort is generally defined recursively. There are ways to do this iteratively using for and while loops, but I definitely don't recommend it as a learning tool until you get it recursively.
Honestly, I suggest taking either my pseudo-code or the pseudo-code you may find in a wikipedia article to implement this and start over with your code. If you do that and it doesn't work correctly still, post it here and we'll help you work out the kinks.
Cheers!
And finally:
// Precondition: array[left..lHigh] is sorted and array[right...rHigh] is sorted.
// Postcondition: array[left..rHigh] contains the same elements of the above parts, sorted.
public static void mergeSort(int[] array, int left, int lHigh, int right, int rHigh) {
// temp[] needs to be as large as the number of elements you're sorting (not half!)
//int elements = (rHigh - lHigh +1) ;
int elements = rHigh - left;
int[] temp = new int[elements];
// this is your index into the temp array
int num = left;
// now you need to create indices into your two lists
int iL = left;
int iR = right;
// Pseudo code... when you code this, make use of iR, iL, and num!
while( temp is not full ) {
if( left side is all used up ) {
copy rest of right side in.
make sure that at the end of this temp is full so the
while loop quits.
}
else if ( right side is all used up) {
copy rest of left side in.
make sure that at the end of this temp is full so the
while loop quits.
}
else if (array[iL] < array[iR]) { ... }
else if (array[iL] >= array[iR]) { ... }
}
}
public class MergeSort {
public static void main(String[] args) {
int[] arr = {5, 4, 7, 2, 3, 1, 6, 2};
print(arr);
new MergeSort().sort(arr, 0, arr.length - 1);
}
private void sort(int[] arr, int lo, int hi) {
if (lo < hi) {
int mid = (lo + hi) / 2;
sort(arr, lo, mid); // recursive call to divide the sub-list
sort(arr, mid + 1, hi); // recursive call to divide the sub-list
merge(arr, lo, mid, hi); // merge the sorted sub-lists.
print(arr);
}
}
private void merge(int[] arr, int lo, int mid, int hi) {
// allocate enough space so that the extra 'sentinel' value
// can be added. Each of the 'left' and 'right' sub-lists are pre-sorted.
// This function only merges them into a sorted list.
int[] left = new int[(mid - lo) + 2];
int[] right = new int[hi - mid + 1];
// create the left and right sub-list for merging into original list.
System.arraycopy(arr, lo, left, 0, left.length - 1);
System.arraycopy(arr, mid + 1, right, 0, left.length - 1);
// giving a sentinal value to marking the end of the sub-list.
// Note: The list to be sorted is assumed to contain numbers less than 100.
left[left.length - 1] = 100;
right[right.length - 1] = 100;
int i = 0;
int j = 0;
// loop to merge the sorted sequence from the 2 sub-lists(left and right)
// into the main list.
for (; lo <= hi; lo++) {
if (left[i] <= right[j]) {
arr[lo] = left[i];
i++;
} else {
arr[lo] = right[j];
j++;
}
}
}
// print the array to console.
private static void print(int[] arr) {
System.out.println();
for (int i : arr) {
System.out.print(i + ", ");
}
}
}
Here's another!
private static int[] mergeSort(int[] input){
if (input.length == 1)
return input;
int length = input.length/2;
int[] left = new int[length];
int[] right = new int[input.length - length];
for (int i = 0; i < length; i++)
left[i] = input[i];
for (int i = length; i < input.length; i++)
right[i-length] = input[i];
return merge(mergeSort(left),mergeSort(right));
}
private static int[] merge(int[] left, int[] right){
int[] merged = new int[left.length+right.length];
int lengthLeft = left.length;
int lengthRight = right.length;
while (lengthLeft > 0 && lengthRight > 0){
if (left[left.length - lengthLeft] < right[right.length - lengthRight]){
merged[merged.length -lengthLeft-lengthRight] = left[left.length - lengthLeft];
lengthLeft--;
}else{
merged[merged.length - lengthLeft-lengthRight] = right[right.length - lengthRight];
lengthRight--;
}
}
while (lengthLeft > 0){
merged[merged.length - lengthLeft] = left[left.length-lengthLeft];
lengthLeft--;
}
while (lengthRight > 0){
merged[merged.length - lengthRight] = right[right.length-lengthRight];
lengthRight--;
}
return merged;
}
static void mergeSort(int arr[],int p, int r) {
if(p<r) {
System.out.println("Pass "+k++);
int q = (p+r)/2;
mergeSort(arr,p,q);
mergeSort(arr,q+1,r);
//System.out.println(p+" "+q+" "+r);
merge(arr,p,q,r);
}
}
static void merge(int arr[],int p,int q,int r) {
int temp1[],temp2[];
//lower limit array
temp1 = new int[q-p+1];
//upper limit array
temp2 = new int[r-q];
for(int i=0 ; i< (q-p+1); i++){
temp1[i] = arr[p+i];
}
for(int j=0; j< (r-q); j++){
temp2[j] = arr[q+j+1];
}
int i = 0,j=0;
for(int k=p;k<=r;k++){
// This logic eliminates the so called sentinel card logic mentioned in Coreman
if(i!= temp1.length
&& (j==temp2.length || temp1[i] < temp2[j])
) {
arr[k] = temp1[i];
// System.out.println(temp1[i]);
i++;
}
else {
//System.out.println(temp2[j]);
arr[k] = temp2[j];
j++;
}
}
}
>
Merge Sort Using Sentinel
This codes works perfectly fine.
public void mergeSort(int a[], int low, int high) {
if (low < high) {
int mid = (low + high) / 2;
mergeSort(a, low, mid);
mergeSort(a, mid + 1, high);
merge(a, low, mid, high);
}
}
public void merge(int a[], int low, int mid, int high) {
int n1 = mid - low + 1;// length of an array a1
int n2 = high - mid; // length of an array a2
int a1[] = new int[n1 + 1];
int a2[] = new int[n2 + 1];
int lowRange = low;
for (int i = 0; i < n1; i++) {
a1[i] = a[lowRange];
lowRange++;
}
for (int j = 0; j < n2; j++) {
a2[j] = a[mid + j + 1];
}
a1[n1] = Integer.MAX_VALUE; // inserting sentinel at the end of array a1
a2[n2] = Integer.MAX_VALUE; // inserting sentinel at the end of array a2
int i = 0;
int j = 0;
int k = low;
for (k = low; k <= high; k++) {
if (a1[i] >= a2[j]) {
a[k] = a2[j];
j++;
} else {
a[k] = a1[i];
i++;
}
}
if (a2.length >= a1.length) {
for (int ab = k; ab < a2.length; ab++) {
a[k] = a2[ab];
k++;
}
} else if (a1.length >= a2.length) {
for (int ab = k; ab < a1.length; ab++) {
a[k] = a1[ab];
k++;
}
}
}
Here's another alternative:
public class MergeSort {
public static void merge(int[]a,int[] aux, int f, int m, int l) {
for (int k = f; k <= l; k++) {
aux[k] = a[k];
}
int i = f, j = m+1;
for (int k = f; k <= l; k++) {
if(i>m) a[k]=aux[j++];
else if (j>l) a[k]=aux[i++];
else if(aux[j] > aux[i]) a[k]=aux[j++];
else a[k]=aux[i++];
}
}
public static void sort(int[]a,int[] aux, int f, int l) {
if (l<=f) return;
int m = f + (l-f)/2;
sort(a, aux, f, m);
sort(a, aux, m+1, l);
merge(a, aux, f, m, l);
}
public static int[] sort(int[]a) {
int[] aux = new int[a.length];
sort(a, aux, 0, a.length-1);
return a;
}
}
Here is a simple merge sort algorithm in Java:
Good Tip: Always use int middle = low + (high-low)/2 instead of int middle = (low + high)/2.
public static int[] mergesort(int[] arr) {
int lowindex = 0;
int highindex = arr.length-1;
mergesort(arr, lowindex, highindex);
return arr;
}
private static void mergesort(int[] arr, int low, int high) {
if (low == high) {
return;
} else {
int midIndex = low + (high-low)/2;
mergesort(arr, low, midIndex);
mergesort(arr, midIndex + 1, high);
merge(arr, low, midIndex, high);
}
}
private static void merge(int[] arr, int low, int mid, int high) {
int[] left = new int[mid-low+2];
for (int i = low; i <= mid; i++) {
left[i-low] = arr[i];
}
left[mid-low+1] = Integer.MAX_VALUE;
int[] right = new int[high-mid+1];
for (int i = mid+1; i <= high; i++) {
right[i-mid-1] = arr[i];
}
right[high - mid] = Integer.MAX_VALUE;
int i = 0;
int j = 0;
for (int k = low; k <= high; k++) {
if (left[i] <= right[j]) {
arr[k] = left[i];
i++;
} else {
arr[k] = right[j];
j++;
}
}
}
package com.sortalgo;
import java.util.Arrays;
public class MyMSort {
private static void merge(int[] array, int[] result, int low, int mid, int high) {
int k =low, i=low; int j=mid+1;
while(i<=mid && j<=high) {
if(array[i]<= array[j]) {
result[k++]=array[i++];
}else {
result[k++]=array[j++];
}
}
while(i<=mid) {
result[k++]=array[i++];
}
while(j<=high) {
result[k++]=array[j++];
}
for(i=low;i<=high;i++) {
array[i]=result[i];
}
}
private static void mergeSort(int[] array, int[] result, int low, int high) {
if(high == low) {
return ;
}
int mid = (low + high)/2;
mergeSort(array,result, low, mid );
mergeSort(array,result, mid+1, high );
merge(array, result, low, mid, high);
}
public static void main(String[] args) {
int[] array = {8,4,3,12,25,6,13,10};
int[] result = new int[array.length];
mergeSort(array, result, 0, array.length-1 );
for(int i=0; i<=array.length-1;i++) {
System.out.println(array[i]);
}
}
}

Categories

Resources