Stack Overflow error in Merge Sort algorithm? - java

I'm writing a merge sort class in java and i get a stack overflow error when I get to the sort(left) line. Any thoughts? I don't understand why this would be a problem.
package ds;
import java.util.Comparator;
public class MergeSorter<T> extends Sorter<T> {
public MergeSorter(Comparator<T> comparator){
super(comparator);
}
#SuppressWarnings("unchecked")
#Override
public void sort(T[] array){
if (array.length <= 1);
else {
T[] left = (T[]) new Object[array.length/2 + 1];
T[] right = (T[]) new Object[array.length/2 + 1];
int middleIndex = array.length / 2;
for (int i = 0; i < middleIndex; i++) {
left[i] = array[i];
}
for (int i = middleIndex; i < array.length; i++) {
right[i - middleIndex] = array[i];
}
sort(left);
sort (right);
merge(left, right, array);
}
}
public final void merge(T[] left, T[] right, T[] array){
Array<T> sortedArray = new Array<T>(array.length);
while (left.length > 0 || right.length > 0) {
if (left.length > 0 && right.length > 0) {
if (comparator.compare(left[0], right[0]) < 0) {
sortedArray.add(left[0]);
for (int i = 1; i < left.length; i++) {
left[i - 1] = left[i];
left[left.length - 1] = null;
}
}
else {
sortedArray.add(right[0]);
for (int i = 1; i < right.length; i++) {
right[i - 1] = right[i];
right[right.length - 1] = null;
}
}
}
else if (left.length > 0) {
sortedArray.add(left[0]);
for (int i = 1; i < left.length; i++) {
left[i - 1] = left[i];
left[left.length - 1] = null;
}
}
else if (right.length > 0) {
sortedArray.add(right[0]);
for (int i = 1; i < right.length; i++) {
right[i - 1] = right[i];
right[right.length - 1] = null;
}
}
}
for (int i = 0; i < array.length; i++) {
array[i] = sortedArray.get(i);
}
}
}

Suppose the array has length 2. Then left is:
T[] left = (T[]) new Object[array.length/2 + 1];
which is
T[] left = (T[]) new Object[2/2 + 1];
and this equals to
T[] left = (T[]) new Object[2];
And when you sort on left, this continues, and leads to an infinite recursion which might have caused the stack overflow error you posted.
Since you are copying the first middleIndex elements into left, middleIndex length should right fit the array left. So left should be a length array.length/2 array.

Related

Shift array elements by n posisition

I've got method to move elements in array, move to right work fine, move to left work incorrect. Method get two incoming parameters:
1st: array
2nd: int variable to move element on this int parameter.
Here is my method:
private static int[] arrShift(int[]arr, int count) {
if (count >= 0) {
for (int i = 0; i < count; i++) {
int temp = arr[arr.length - 1];
for (int j = arr.length - 2; j > -1; j--) {
arr[j + 1] = arr[j];
}
arr[0] = temp;
}
}
if (count < 0){
count *=-1;
int temp = arr[0];
for (int i = 0; i < count; i++) {
for (int j = 0; j < arr.length -1; j++) {
arr[j] = arr[j + 1];
}
}
arr[0] = temp;
}
return arr;
}
How shift elements to left?
This should work like a charm :)
private static int[] arrShift(int[]arr, int count) {
if (count >= 0) {
for (int i = 0; i < count; i++) {
int temp = arr[arr.length - 1];
for (int j = arr.length - 2; j > -1; j--) {
arr[j + 1] = arr[j];
}
arr[0] = temp;
}
}
if (count < 0){
count *=-1;
for (int i = 0; i < count; i++) {
int temp = arr[0];
for (int j = 0; j < arr.length -1; j++) {
arr[j] = arr[j + 1];
}
arr[arr.length - 1] = temp;
}
}
return arr;
}

Finding sorted subarrays in array

I am working on sorting algorithms and I am trying to improve mergeSort by locating already sorted subArrays.
public static void mergeSort(int[] array)
{
if(array == null)
{
return;
}
if(array.length > 1)
{
int mid = array.length / 2;
// left
int[] left = new int[mid];
for(int i = 0; i < mid; i++)
{
left[i] = array[i];
}
//right
int[] right = new int[array.length - mid];
for(int i = mid; i < array.length; i++)
{
right[i - mid] = array[i];
}
//recursively calls
mergeSort(left);
mergeSort(right);
int i = 0;
int j = 0;
int k = 0;
// left and right merged
while(i < left.length && j < right.length)
{
if(left[i] < right[j])
{
array[k] = left[i];
i++;
}
else
{
array[k] = right[j];
j++;
}
k++;
}
// left overs
while(i < left.length)
{
array[k] = left[i];
i++;
k++;
}
while(j < right.length)
{
array[k] = right[j];
j++;
k++;
}
}
}
What you are looking for is called natural merge sort. Before you start with sorting the dataset you will do one run to identify all the presorted data. The mergesort itself stays the same.
I found some example code for you at: happycoders
package eu.happycoders.sort.method.mergesort;
import eu.happycoders.sort.method.Counters;
import eu.happycoders.sort.method.SortAlgorithm;
/**
* Natural merge sort implementation for performance tests.
*
* #author Sven Woltmann
*/
public class NaturalMergeSort implements SortAlgorithm {
#Override
public void sort(int[] elements) {
int numElements = elements.length;
int[] tmp = new int[numElements];
int[] starts = new int[numElements + 1];
// Step 1: identify runs
int runCount = 0;
starts[0] = 0;
for (int i = 1; i <= numElements; i++) {
if (i == numElements || elements[i] < elements[i - 1]) {
starts[++runCount] = i;
}
}
// Step 2: merge runs, until only 1 run is left
int[] from = elements;
int[] to = tmp;
while (runCount > 1) {
int newRunCount = 0;
// Merge two runs each
for (int i = 0; i < runCount - 1; i += 2) {
merge(from, to, starts[i], starts[i + 1], starts[i + 2]);
starts[newRunCount++] = starts[i];
}
// Odd number of runs? Copy the last one
if (runCount % 2 == 1) {
int lastStart = starts[runCount - 1];
System.arraycopy(from, lastStart, to, lastStart,
numElements - lastStart);
starts[newRunCount++] = lastStart;
}
// Prepare for next round...
starts[newRunCount] = numElements;
runCount = newRunCount;
// Swap "from" and "to" arrays
int[] help = from;
from = to;
to = help;
}
// If final run is not in "elements", copy it there
if (from != elements) {
System.arraycopy(from, 0, elements, 0, numElements);
}
}
private void merge(int[] source, int[] target, int startLeft,
int startRight, int endRight) {
int leftPos = startLeft;
int rightPos = startRight;
int targetPos = startLeft;
// As long as both arrays contain elements...
while (leftPos < startRight && rightPos < endRight) {
// Which one is smaller?
int leftValue = source[leftPos];
int rightValue = source[rightPos];
if (leftValue <= rightValue) {
target[targetPos++] = leftValue;
leftPos++;
} else {
target[targetPos++] = rightValue;
rightPos++;
}
}
// Copy the rest
while (leftPos < startRight) {
target[targetPos++] = source[leftPos++];
}
while (rightPos < endRight) {
target[targetPos++] = source[rightPos++];
}
}
#Override
public void sort(int[] elements, Counters counters) {
// Not implemented
}
}

Merge sort algorithm not working

Here is my code for a mergesort in java:
public class MergeSort {
public static void mergesort(int[] input) {
int inputSize = input.length;
if(inputSize < 2) {
return;
}
int[] left = new int[inputSize/2];
int[] right = new int[inputSize/2];
int count = 0;
for(int i=0; i < inputSize/2; i++) {
left[i] = input[i];
}
for(int i=inputSize/2; i<inputSize; i++) {
right[count] = input[i];
count++;
}
mergesort(left);
mergesort(right);
merge(left, right, input);
}
public static int[] merge(int[] returnArr, int[] left, int[] right) {
int leftSize = left.length;
int rightSize = right.length;
int i = 0;
int j =0;
int k = 0;
int count = 0;
while(i < leftSize && j < rightSize) {
if(left[i] <= right[j]) {
returnArr[k] = left[i];
i++;
}
else {
returnArr[k] = right[j];
j++;
}
k++;
}
while(i<leftSize) {
returnArr[k] = left[i];
i++;
k++;
}
while(j < rightSize) {
returnArr[k] = right[j];
j++;
k++;
}
for(int x=0; x<returnArr.length; x++) {
System.out.print(returnArr[x]);
}
return returnArr;
}
public static void main(String[] args) {
int[] array = {3,4,6,2,7,1,8,6};
mergesort(array);
}
}
My issue is that I'm getting an out of bounds exception.
I'm using the debugger and have found that after mergesort(left) and mergesort(right) have finished recursively running.
The arrays left and right, which go into the merge function, have the values [3] and [4] respectively, which is correct.
But when the debugger jumps into the merge function, left has value [3] and right, for some reason is length 2 and has the value [3,4].
This is the source of my out of bounds exception, though I'm not sure why when the merge function runs for its first time, it changes the value of "right".
One problem that is readily visible is that the you shouldn't make 2 arrays of size inputSize/2. Make two arrays of inputSize/2 and inputsize-inputSize/2. Otherwise the algorithm would fail for odd length array.
Also call the function with proper order of the arguments. merge( input, left, right);
I fixed your code and merged them to 1 method, left.length and right.length are limited by input.length so you only need to loop by input.length:
public static void mergeSort(int[] input)
{
if (input.length < 2)
{
return;
}
int[] left = new int[input.length / 2];
int[] right = new int[input.length - input.length / 2];
for (int i = 0; i < input.length; i++)
{
if (i < input.length / 2)
left[i] = input[i];
else
right[i - input.length / 2] = input[i];
}
mergeSort(left);
mergeSort(right);
for (int i = 0, l = 0, r = 0; i < input.length; i++)
{
if (l >= left.length)
{
input[i] = right[r];
r++;
}
else if (r >= right.length)
{
input[i] = left[l];
l++;
}
else
{
if (left[l] >= right[r])
{
input[i] = right[r];
r++;
}
else
{
input[i] = left[l];
l++;
}
}
}
}
you had two problems with your code:
1- as #coderredoc said: your left and right array sizes are wrong:
exemple: if you had an array of 7 elements, your left and right arrays would have a size of 7/2 = 3 so you would have a total of 6 elements in left and right arrays and not 7.
2- you are calling merge function in the mergeSort function with wrong parameters order:
it should be returnArr, left, right and not left,right, returnArr.
Explanation:
if you pass the left array as the first parameter, it would merge the right and the returnArr in the left array. But your left array has a size of 3 and the sum of the sizes of the others is 7 + 3 = 10 that's why you got an OutOfBoundsException.
you need to call merge(input,left,right);
here is the final version:
public class MergeSort {
public static void mergesort(int[] input) {
int inputSize = input.length;
if(inputSize < 2) {
return;
}
int[] left = new int[inputSize/2];
int[] right = new int[inputSize-inputSize/2];
int count = 0;
for(int i=0; i < inputSize/2; i++) {
left[i] = input[i];
}
for(int i=inputSize/2; i<inputSize; i++) {
right[count] = input[i];
count++;
}
mergesort(left);
mergesort(right);
merge(input,left, right);
}
public static int[] merge(int[] returnArr, int[] left, int[] right) {
int leftSize = left.length;
int rightSize = right.length;
int i = 0;
int j =0;
int k = 0;
int count = 0;
while(i < leftSize && j < rightSize) {
if(left[i] <= right[j]) {
returnArr[k] = left[i];
i++;
}
else {
returnArr[k] = right[j];
j++;
}
k++;
}
while(i<leftSize) {
returnArr[k] = left[i];
i++;
k++;
}
while(j < rightSize) {
returnArr[k] = right[j];
j++;
k++;
}
for(int x=0; x<returnArr.length; x++) {
System.out.print(returnArr[x]);
}
return returnArr;
}
public static void main(String[] args) {
int[] array = {3,4,6,2,7,1,8,6};
mergesort(array);
}
}

How to fix NullPointerException in For Loop [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
So I am sort of new to Java and have only been doing it for a couple of months. I'm trying to implement different types of sorting algorithms and I think everything is okay except when I run it I get a NullPointerException on the for loop. I have already read this post What is a NullPointerException, and how do I fix it?. But I still can not figure out how to fix the problem even though I think it is quite simple. Any help?
import java.lang.*;
import java.util.*;
public class SortApp {
public int[] generateRandomArray(int size) {
int[] output = new int[size];
for (int i = 0; i < size; i++) {
output[i] = (int) (Math.random() * Integer.MAX_VALUE);
}
return output;
}
public void printArray(int[] inarray) {
for (int i = 0; i < inarray.length; i++) {
System.out.println(inarray[i]);
}
}
public boolean isSorted(int[] inarray) {
for (int i = 0; i < inarray.length; i++) { //Error here
if (inarray[i] > inarray[i + 1]) {
return false;
}
}
return true;
}
public int[] insertionSort(int[] inarray) {
int[] data = Arrays.copyOf(inarray, inarray.length);
int temp;
int j;
for (int i = 0; i < inarray.length; i++) {
temp = inarray[i];
for (j = 0; (j > 1) && (temp < inarray[j - 1]); j--)
inarray[j] = inarray[j - 1];
inarray[j] = temp;
}
return data;
}
public int[] selectionSort(int[] inarray) {
int[] data = Arrays.copyOf(inarray, inarray.length);
int temp;
int n = inarray.length;
for (int i = 0; i < inarray.length; i++) {
int k = i;
for (int j = i + 1; j < n; j++)
if (inarray[j] < inarray[k])
k = j;
temp = inarray[i];
inarray[i] = inarray[k];
inarray[k] = temp;
}
return data;
}
public int[] mergeSort(int[] inarray, int temp[], int l, int r) {
int[] data = Arrays.copyOf(inarray, inarray.length);
if (l == r) return null;
int mid = (l + r) / 2;
mergeSort(inarray, temp, l, mid);
mergeSort(inarray, temp, mid + 1, r);
int i, j, k;
for (i = l; i <= r; i++)
temp[i] = inarray[i];
for (i = l, j = mid + 1, k = l; i <= mid && j <= r && k <= r; k++)
if (temp[i] < temp[j]) inarray[k] = temp[i];
i++;
inarray[k] = temp[j];
j++;
for (; i <= mid; i++, k++)
inarray[k] = temp[i];
for (; j <= r; j++, k++)
inarray[k] = temp[j];
return data;
}
public static void main(String[] args) {
SortApp myApp = new SortApp();
int[] data = myApp.generateRandomArray(10);
boolean isSortedA = myApp.isSorted(myApp.insertionSort(data));
boolean isSortedB = myApp.isSorted(myApp.selectionSort(data));
boolean isSortedC = myApp.isSorted(myApp.mergeSort(data, data, 0, 0)); //Error here
myApp.printArray(data);
}
}
Error I am getting is this:
Exception in thread "main" java.lang.NullPointerException
at SortApp.isSorted(SortApp.java:23)
at SortApp.main(SortApp.java:91)
It's because of this line:
if (l==r) return null;
You are passing in 0 for both l and r meaning they are equal. Therefore, you are getting a null value passed in to your isSorted() call.

Print elements of a matrix in diagonal stripes

I want to generate a matrix with consecutive numbers starting from 1, in this form
zig zag matrix
public static int[][] Zig_Zag(final int size) {
int[][] data = new int[size][size];
int i = 1;
int j = 1;
for (int element = 0; element < size * size; element++) {
data[i - 1][j - 1] = element;
if ((i + j) % 2 == 0) { // Even stripes if (j < size) j++; else i+=
// 2; if (i > 1) i--; } else { // Odd
// stripes if (i < size) i++; else j+= 2; if
// (j > 1) j--; } } return data; }
}
}
return data;
}
Can anybody help?
Try this
public static int[][] Zig_Zag(int size) {
int[][] a = new int[size][size];
int n = 1;
for (int r = size, c = 0; r >= 0; --r)
for (int i = r, j = c; i < size; ++i, ++j)
a[i][j] = n++;
for (int r = 0, c = 1; c < size; ++c)
for (int i = r, j = c; j < size; ++i, ++j)
a[i][j] = n++;
return a;
}
and
int[][] a = Zig_Zag(4);
for (int[] r : a)
System.out.println(Arrays.toString(r));
result:
[7, 11, 14, 16]
[4, 8, 12, 15]
[2, 5, 9, 13]
[1, 3, 6, 10]
Try this code :
public static int[][] Zig_Zag(final int size) {
int[][] data = new int[size][size];
int i = 1;
int j = 1;
for (int element = 1; element <= size * size; element++) {
data[i - 1][j - 1] = element;
if ((i + j) % 2 == 0) {
// Even stripes
if (j < size)
j++;
else
i += 2;
if (i > 1)
i--;
} else {
// Odd stripes
if (i < size)
i++;
else
j += 2;
if (j > 1)
j--;
}
}
return data;
}
public static void main(String[] args) {
int[][] data = Zig_Zag(4);
for(int i=0; i<data.length;i++){
for(int j=0; j<data[i].length;j++){
System.out.print(data[i][j]+" ");
}
System.out.println("");
}
}
Output:
1 2 6 7
3 5 8 13
4 9 12 14
10 11 15 16
Not a very elegant solution:
private static int triangle_below(int n) {
return n * (n + 1) / 2;
}
private static int except_triangle_above(int size, int n) {
return size * size - triangle_below(2 * size - n);
}
private static int[][] gen(int size) {
int[][] m = new int[size][size];
for (int i = 0; i < size; ++i) {
for (int j = 0; j < size; ++j) {
// already filled cells in lower diagonal layers
int k = Math.min(
triangle_below(i + j),
except_triangle_above(size, Math.max(size, i + j + 1))
);
// position in current layer
int l = Math.min(j + 1, size - i);
m[size - i - 1][j] = k + l;
}
}
return m;
}

Categories