I'm in an algorithms course and am learning about merge sort. Our professor recommended we try to implement the pseudo code provided in the book.
Am I correct in using Integer.MAX_VALUE as a sentinel value when
sorting an array of integers (used in lines 8 & 9 in the Merge
method pseudo code below)?
For line 2 of the Merge-Sort pseudo code method, is it correct to code that in Java using Math.ceil() like I did? (Edit: It's actually floor and I updated my code to reflect this.)
If you see any other mistakes please let me know!
Here is the pseudo code the book gives for merge sort.
And, here is how I coded it in Java:
public void mergeSort(int[] arrNums, int p, int r) {
if (p < r) {
int q = (p + r) / 2;
mergeSort(arrNums, p, q);
mergeSort(arrNums, q + 1, r);
merge(arrNums, p, q, r);
}
}
public void merge(int[] arrNums, int p, int q, int r) {
int nOne = q - p + 1;
int nTwo = r - q;
int[] arrLeft = new int[nOne + 1];
int[] arrRight = new int[nTwo + 1];
for (int i = 0; i < nOne; i++) {
arrLeft[i] = arrNums[p + i - 1];
}
for (int j = 0; j < nTwo; j++) {
arrRight[j] = arrNums[q + j];
}
arrLeft[nOne] = Integer.MAX_VALUE;
arrRight[nTwo] = Integer.MAX_VALUE;
// Tracks arrLeft index
int i = 0;
// Tracks arrRight index
int j = 0;
for (int k = p; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
}
The last for loop in your merge method, variable k should start from p - 1:
for (int k = p - 1; k < r; k++) {
if (arrLeft[i] <= arrRight[j]) {
arrNums[k] = arrLeft[i];
i++;
} else {
arrNums[k] = arrRight[j];
j++;
}
}
Pseudo code in many text books likes to start array index from 1, so here you need to subtract it by 1.
I implemented it a few days ago, if someone will be interested.
private static void mergeSort(double[] arr, int start, int end){
if(start < end){
int mid = ( start + end ) / 2;
mergeSort(arr, start, mid);
mergeSort(arr, mid + 1, end);
Merge(arr, start, mid, end);
}
}
private static void Merge(double[] arr, int start, int mid, int end){
double[] leftArray = new double[mid - start + 2];
double[] rightArray = new double[end - mid + 1];
for(int i = start; i <= mid; i++ )
leftArray[i - start] = arr[i];
for (int i = mid + 1; i <= end; i++ )
rightArray[i - mid - 1] = arr[i];
leftArray[mid - start + 1] = Double.POSITIVE_INFINITY;
rightArray[end - mid] = Double.POSITIVE_INFINITY;
int leftIndex = 0, rightIndex = 0;
for (int k = start; k <= end; k++){
if(leftArray[leftIndex] <= rightArray[rightIndex])
arr[k] = leftArray[leftIndex++];
else
arr[k] = rightArray[rightIndex++];
}
}
Related
This my introductory course to Algorithms, and I understand algorithms and I can design them, but this is the first time I tryed to apply it in java code, please tell me what i did wrong in this code for it to not work properly
I'm trying to apply this algorithm ,
this is the rest of the algorithm
This is my main void:
int[] A = { 5, 2, 4, 7, 1, 3, 2, 6 };
int p = 1;
int r = A.length;
Main obi = new Main ();
obi.mergeSort (A, p, r);
my first function:
public void mergeSort (int[]A, int p, int r) {
if (p < r){
int q = (p + r) / 2;
mergeSort (A, p, q);
mergeSort (A, q + 1, r);
merge (A, p, q, r);
}
}
my second function:
public void merge (int[]A, int p, int q, int r) {
int n1 = q - p + 1;
int n2 = r - q;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; i++){
L[i] = A[p + i - 1];
}
for (int j = 0; j < n2; j++){
R[j] = A[q + j];
}
int i = 0;
int j = 0;
for (int k = p - 1; k < r; k++){
if (L[i] <= R[j]){
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
}
And this is the error message I got:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
at Main.merge(Main.java:44)
at Main.mergeSort(Main.java:19)
at Main.mergeSort(Main.java:17)
at Main.mergeSort(Main.java:17)
at Main.main(Main.java:10)
I tried to let L[] and R[] have length n1+1 and n2+1 but it didn't help.
There are multiple problems in your code:
the arguments r and q should be the index of the first element in the slice, hence int p = 0; in main() instead of 1, and the index past the last element in the slice, hence correctly int r = A.length;
With this convention, there is no need for confusing and error prone +1/-1 adjustments in the merge and mergeSort methods.
Furthermore, the merging loop in merge should be modified to avoid accessing L[i] or R[j] when the corresponding index reaches the length of the array.
Here is a modified version:
...
int[] A = { 5, 2, 4, 7, 1, 3, 2, 6 };
int p = 0;
int r = A.length;
Main obi = new Main();
obi.mergeSort(A, p, r);
...
public void mergeSort(int[]A, int p, int r) {
if (r - p > 1) {
int q = p + (r - p) / 2;
mergeSort(A, p, q);
mergeSort(A, q, r);
merge(A, p, q, r);
}
}
public void merge(int[]A, int p, int q, int r) {
int n1 = q - p;
int n2 = r - q;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; i++) {
L[i] = A[p + i];
}
for (int j = 0; j < n2; j++) {
R[j] = A[q + j];
}
int i = 0;
int j = 0;
for (int k = p; k < r; k++) {
if (i < n1 && (j >= n2 || L[i] <= R[j])) {
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
}
Note that the merge method can be simplified as the elements of the second half never get overwritten before they are moved into their final spot, so there is no need to save them:
public void merge(int[]A, int p, int q, int r) {
int n1 = q - p;
int L[] = new int[n1];
for (int i = 0; i < n1; i++) {
L[i] = A[p + i];
}
int i = 0;
int j = q;
int k = p;
while (i < n1) {
if (j >= r || L[i] <= A[j])
A[k++] = L[i++];
else
A[k++] = A[j++];
}
}
Either L or R finishes first.
for (int k = p - 1; k < r; k++){
if (L[i] <= R[j]){
A[k] = L[i];
i = i + 1;
} else {
A[k] = R[j];
j = j + 1;
}
}
Lets say L finishes first then i becomes L.length+1 so that when the next iteration occurs L[i] is invalid as its one past the end.
So the problem that I am running into is that I am trying to get my merge sort implementation to run, but I keep getting an Exception error that says the Array index is out of bounds. This is a runtime error because I am able to compile the program with no issues and it will run up until it hits my merge sort call. One thing that I tried was changing one of my variables to match the other within the merge method (int k = 0; //line 39). When I did this, the code ran, however, the merge sorted array was not correct. I even tried debugging the code, but couldn't see an issue with it. Below is my code:
public static void merge_sort(int A[], int l, int r){
if(l < r){
int m = (l + r)/2;
merge_sort(A, l, m);
merge_sort(A, m + 1, r);
merge(A, l, m, r);//Line17
}
}
public static void merge(int A[], int l, int m, int r){
int n1 = m - l + 1;
int n2 = r - m;
int L[] = new int [n1];
int R[] = new int [n2];
for(int i = 0; i < n1; i++){
L[i] = A[l + i];
}
for(int j = 0; j < n2; j++){
R[j] = A[m + 1 + j];
}
int i = 0;
int j = 0;
int k = 1; //line39
while(i < n1 && j < n2){
if(L[i] <= R[j]){
A[k] = L[i];
i++;
}
else{
A[k] = R[j];
j++;
}
k++;
}
while(i < n1){
A[k] = L[i];
i++;
k++;
}
while(j < n2){
A[k] = R[j]; //line60
j++;
k++;
}
}
And here is the error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 15
at HW3.merge(HW3.java:60)
at HW3.merge_sort(HW3.java:17)
at HW3.main(HW3.java:160) //this line is where I call the method within the main
I understand that this means that the array is going out of the set size of 15 but I am unsure of how to fix this issue. I have tried looking at similar problems, but I did not see a solution to the issue I was having.
Everything else is fine in your code.
Except for this line
int k = 1; //line39
this should be k = l (The letter 'L' in small caps)
You can refer the following code
public class StackExchange {
public static
void mergeSort(int A[], int l , int r) {
if (l < r) {
int m = (l+r)/2;
mergeSort(A, l , m);
mergeSort(A, m+1, r);
merge(A, l, m, r);
}
}
private static void merge(int[] A, int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0 ; i < n1; i++) {
L[i] = A[l+i];
}
for (int j = 0 ; j < n2; j++) {
R[j] = A[m + 1 + j];
}
int i = 0, j = 0 , k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
} else {
A[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
A[k] = L[i];
i++;
k++;
}
while (j < n2) {
A[k] = R[j];
j++;
k++;
}
}
public static void main (String...s) {
int array[] = new int[] {12, 21, 32, 36, 14, 10, 11, 5, 55, 16, 31, 7, 57, 89, 78};
mergeSort(array, 0, array.length - 1);
printArray(array);
}
private static void printArray(int array[]) {
for (int i : array) {
System.out.println(i + " -- ");
}
}
}
How are you calling your function ? Make sure that you are using object.sort(arr, 0, A.length-1); in main when you pass the max value of the array index.
here example
// Initial index of merged subarry array
int k = l; //this is L not a 1
I'm using the pseudocode called Lomuto partition scheme on https://en.wikipedia.org/wiki/Quicksort. But I just don't understand what it is that I am doing wrong here. The array never gets organized (regardless of the input size). This is preparation for my final exam. My professor wants us to use this algorithm, but I can't just learn it unless I have an understanding of how it works by testing it.
private static void quickSort(Integer A[], int l, int r) {
if (l < r) {
int k = partition(A, l, r);
quickSort(A, l, k - 1);
quickSort(A, k + 1, r);
}
}
private static int partition(Integer A[], int l, int r) {
int pivot = A[r];
int i = l;
for (int j = l; j <= r - 1; j++) {
if (A[j] <= pivot) {
i++;
int temp = A[j];
A[j] = pivot;
pivot = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
I don't know what else to say other than that you just didn't transcribe the pseudocode correctly. At the beginning of partition, i should equal l - 1, but you set it to l.
Also, you're not swapping A[i] with A[j] within the nested loop. Here's the correct implementation:
private static int partition(Integer A[], int l, int r) {
int pivot = A[r];
int i = l - 1;
for (int j = l; j <= r - 1; j++) {
if (A[j] < pivot) {
i++;
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
int temp = A[i + 1];
A[i + 1] = A[r];
A[r] = temp;
return i + 1;
}
I am trying make an iterative version of Merge Sort for an Assignment. I got the Merge sort method from a website, and I worked on the method that is supposed to merge the arrays. However I keep getting an IndexOutOfBounds Exception.
I have been working on this for multiple hours and I cannot find the error. Can someone help me find a way to solve this?
So far I have this:
public static void MergeSort(int[] array) {
int current;
int leftStart;
int arraySize = array.length - 1;
for (current = 1; current <= arraySize; current = 2 * current) {
for (leftStart = 0; leftStart <= arraySize; leftStart += 2 * current) {
int mid = leftStart + current - 1;
int right = getMin(leftStart + 2 * current - 1, arraySize);
mergeArray(array, leftStart, mid, right);
}
}
}
public static void mergeArray(int[] array, int left, int mid, int right) {
int leftArraySize = mid - left + 1;
int rightArraySize = right - mid;
int[] leftArray = new int[leftArraySize];
int[] rightArray = new int[rightArraySize];
for (int i = 0; i < leftArraySize; i++)
leftArray[i] = array[left + i];
for (int i = 0; i < rightArraySize; i++)
rightArray[i] = array[mid + 1 + i];
int leftPtr = 0;
int rightPtr = 0;
int tempPtr = leftPtr;
while (leftPtr < leftArraySize && rightPtr < rightArraySize) {
if (leftArray[leftPtr] <= rightArray[rightPtr])
array[tempPtr++] = leftArray[leftPtr++];
else
array[tempPtr++] = rightArray[rightPtr++];
}
while (leftPtr <= left)
array[tempPtr++] = leftArray[leftPtr++];
while (rightPtr < right)
array[tempPtr++] = rightArray[rightPtr++];
}
public static int getMin(int left, int right) {
if (left <= right) {
return left;
} else {
return right;
}
}
Any sort of help will be highly appreciated!
Thanks!
Merge sort algorithm is a classical Divide and Conquer algorithm.
Divide the problem into smaller sub problems
Conquer via recursive calls.
Combine solutions of sub problems into one for the original problem
The Pseudocode for Merge:
C = output[length = n]
A = 1st sorted array[n/2]
B = 2st sorted array[n/2]
i = 1
j = 1
for k = 1 to n
if A[i] < B[j]
C[k] = A[i]
i++
else B[j]<A[i]
C[k] = B[j]
j++
end (ignores end cases)
So your source code problem is this line:
array[tempPtr++] = leftArray[leftPtr++];
please change to the logic of pseudocode:
if (leftArray [leftPtr ] <= rightArray[rightPtr ])
{
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
}
else
{
array[tempPtr] = rightArray[rightPtr];
rightPtr++;
}
Try this code Successfully executed:
Only Small mistake in mergeArray() method:
array[tempPtr++] = leftArray[leftPtr++];
DOn't increment in array... Replace
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
Final code: Compare my code you will get it.
public static void MergeSort(int[] array) {
int current;
int leftStart;
int arraySize = array.length;
for (current = 1; current <= arraySize-1; current = 2 * current) {
for (leftStart = 0; leftStart < arraySize-1; leftStart += 2 * current) {
int mid = leftStart + current - 1;
int right = getMin(leftStart + 2 * current - 1, arraySize-1);
mergeArray(array, leftStart, mid, right);
}}}
static void printArray(int A[])
{
int i;
for (i=0; i < A.length; i++)
System.out.println(A[i]);
}
static void mergeArray(int array[], int left, int mid, int right)
{
int leftArraySize = mid - left + 1;
int rightArraySize = right - mid;
int[] leftArray = new int[leftArraySize];
int[] rightArray = new int[rightArraySize];
for (int i = 0; i < leftArraySize ; i++)
leftArray [i] = array[left + i];
for (int j = 0; j < rightArraySize; j++)
rightArray[j] = array[mid + 1+ j];
int leftPtr = 0;
int rightPtr = 0;
int tempPtr = left;
while (leftPtr < leftArraySize && rightPtr < rightArraySize)
{
if (leftArray [leftPtr ] <= rightArray[rightPtr ])
{
array[tempPtr] = leftArray [leftPtr];
leftPtr++;
}
else
{
array[tempPtr] = rightArray[rightPtr];
rightPtr++;
}
tempPtr++;
}
while (leftPtr < leftArraySize )
{
array[tempPtr++] = leftArray [leftPtr++];
leftPtr++;
tempPtr++;
}
while (rightPtr < rightArraySize)
{
array[tempPtr++] = rightArray[rightPtr++];
rightPtr++;
tempPtr++;
} }
public static int getMin(int left, int right) {
if (left <= right) {
return left;
} else {
return right;
}}
I cannot guess what is wrong with my code.
INPUT:10, 7, 8, 9, 1, 5
OUTPUT:5 7 9 8 10 1
public class QuickSort {
public static void quickSort(int arr[], int p, int r) {
if (p < r) {
// System.out.println(p+" "+r);
int q = partition(arr, p, r);
quickSort(arr, p, q - 1);
quickSort(arr, q + 1, r);
}
}
public static int partition(int arr[], int p, int r) {
int pivot = arr[r];
int i = p - 1;
for (int j = p; j < r - 1; j++) {
// System.out.println("j");
if (arr[j] <= pivot) {
i = i + 1;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[r];
arr[r] = temp;
return i + 1;
}
static void printArray(int arr[]) {
int n = arr.length;
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
System.out.println();
}
}
Please clarity my doubt,where to change code so that it works fine.
You are not iterating to the end of the loop (last element). Hence the partition function will not seperate the elements correctly as smaller to the left of pivot and larger to the right of pivot.
Your for loop
for (int j = p; j < r - 1; j++) {
change to
for (int j = p; j <= r - 1; j++) {
Now it is working fine.
See here Ideone