Lets say I have a class called "Sequence". This class has an instance variable private int[] tab.
There are also some methods to create this tab like those:
public Sequence() {
this.tab = fillAnArray(drawsNumber(5, 20));
}
private int drawsNumber(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("Wrong range");
}
return new Random().nextInt(max - min + 1) + min;
}
public int[] fillAnArray(int size) {
int[] arr = new int[size];
arr[0] = 1;
for (int i = 1; i < arr.length; i++) {
arr[i] = drawsNumber(arr[i - 1], arr[i - 1] + 10);
}
return arr;
}
Now, I would like to create the method that accepts two Sequence objects as arguments and returns number of the same tab elements. So, I created method like this:
public int howManyCommonElements(Sequence c1, Sequence c2) {
int i = 0, j = 0;
int counter = 0;
while (i < c1.tab.length && j < c2.tab.length) {
if (c1.tab[i] == c2.tab[j]) {
++counter;
} else if (c1.tab[i] < c2.tab[j]) {
++i;
} else {
++j;
}
}
return counter;
}
How do I compare single elements like c1.tab[i], c2.tab[j]?
You have to compare every element of the 1st array with every element of the 2nd one. To do that you have to use 2 nested for cycles:
for (int i = 0; i < c1.tab.length; i++)
for (int j = 0; j < c2.tab.length; j++)
if (c1.tab[i] == c2.tab[j])
++counter;
If you have ordered elements (ASC), you can do like;
int i = 0, j = 0;
int counter = 0;
while (i < arr1.length && j < arr2.length) {
if (arr1[i] == arr2[j]) {
++i;
++j;
++counter;
} else if (arr1[i] < arr2[j]) {
++i;
} else {
++j;
}
}
Related
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
}
}
I am trying to implement a solution to merge two sorted arrays to a single sorted array.
I tried to implement a code but it does not work. The issue that I am seeing here is after my outer for loop reaches the limit of array2.length(), it still gets started from i=0. Can someone please help explain whats wrong in this piece of code?
List<Integer> mergedArray = new ArrayList<>();
int counter = 0;
public List<Integer> getMergedArray(List<Integer> array1, List<Integer> array2) {
for (int i = 0; i < array1.size(); i++) {
for (int j = counter; j < array2.size(); j++) {
if (array1.get(i) > array2.get(j)) {
mergedArray.add(array2.get(j));
counter++;
} else {
mergedArray.add(array1.get(i));
System.out.println("i " +i);
break;
}
}
}
return mergedArray;
}
One problem I see with the code is when the two arrays do not have same length. In either case of (array1.length > array2.length or reverse) the remaining elements of longer array will not be processed. So if you add a more code at end of this the loops to deal with that case, this might work well!
public List<Integer> getMergedArray(List<Integer> array1, List<Integer> array2) {
List<Integer> mergedArray = new ArrayList<>();
int counter = 0, i = 0, j = 0;
for (i = 0; i < array1.size(); i++) {
for (j = counter; j < array2.size(); j++) {
if (array1.get(i) > array2.get(j)) {
mergedArray.add(array2.get(j));
counter++;
} else {
mergedArray.add(array1.get(i));
System.out.println("i " +i);
break;
}
}
}
// More code here
if (j==array2.size()){//copy rest of array1 into mergedArray}
if (i==array1.size()){//copy rest of array2 into mergedArray}
return mergedArray;
}
I think you called the same method twice, without resetting the counter or the previous mergedArray.
You should declare those inside the method.
Additionally, after reaching the end of array1, you should check if there are remaining elements in array2, and vice-versa:
public List<Integer> getMergedArray(List<Integer> array1, List<Integer> array2) {
List<Integer> mergedArray = new ArrayList<>();
int counter = 0;
for (int i = 0; i < array1.size(); i++) {
for (int j = counter; j < array2.size(); j++) {
if (array1.get(i) > array2.get(j)) {
mergedArray.add(array2.get(j));
counter++;
} else {
mergedArray.add(array1.get(i));
System.out.println("i " +i);
break;
}
}
if(counter >= array2.size()) {
mergedArray.add(array1.get(i));
}
}
for (int j = counter; j < array2.size(); j++) {
mergedArray.add(array2.get(j));
}
return mergedArray;
}
I think it works but problem is that you don't handle case when inner array size is equal or bigger than size of outer array. I rewrote your method (in way I think it`s right). Hope you'll find it useful.
public List<Integer> getMergedArray(List<Integer> array1, List<Integer> array2) {
List<Integer> mergedArray = new ArrayList<>();
int index1 = 0;
int index2 = 0;
for (int i = 0; i < array1.size() + array2.size(); i++) {
Integer num1 = null;
Integer num2 = null;
if (index1 < array1.size()) {
num1 = array1.get(index1);
}
if (index2 < array2.size()) {
num2 = array2.get(index2);
}
if (num1 != null && num2 != null) {
if (num1 < num2) {
mergedArray.add(num1);
++index1;
} else {
mergedArray.add(num2);
++index2;
}
} else if (num1 != null) {
mergedArray.add(num1);
++index1;
} else {
mergedArray.add(num2);
++index2;
}
}
return mergedArray;
}
If your array2 has all the element less then array1[i]
in this case your logic also fails because your inner loop condition always fail
you can do this way
int i = 0, j = 0;
int k = l;
while (i < n1 && j < n2) {
if (arry1[i] <= arry2[j]) {
TempArry[k] = arry1[i];
i++;
}
else {
TempArry[k] = arry2[j];
j++;
}
k++;
}
/* Copy remaining elements of array1[] if any */
while (i < n1) {
TempArry[k] = array1[i];
i++;
k++;
}
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);
}
}
My task is to write a function that rearranges an array so that the odd numbers occur in the beginning of the array, from greatest to least, and the even numbers from least to greatest at the end. We are not allowed to use any other libraries except for the standard input and output streams.
The output works when the numbers are:
{-15, 450, 6, -9, 54}
But if I changed the elements to:
{-55, 45, 6, 11, 54}
There is an exception error. Here is my code:
public class ary1 {
public static void sort(int A[], int n) {
int tmp;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (A[0] % 2 == 0) //even
{
if (A[i] < A[j]) {
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
} else {
if (A[i] > A[j]) {
tmp = A[i];
A[i] = A[j];
A[j] = tmp;
}
}
}
}
}
public static void showAray(int A[], int n) {
for (int i = 0; i < n; i++) {
System.out.println(A[i]);
}
}
public static void main(String args[]) {
int array1[] = {-55, 45, 6, 11, 54};
int odd = 0;
int even = 0;
for (int i = 0; i < array1.length; i++) {
if (array1[i] % 2 == 0) {
even++;
} else {
odd++;
}
}
int[] array2 = new int[even];
int[] array3 = new int[odd];
for (int i = 0, j = 0, k = 0; i < array1.length; i++) {
if (array1[i] % 2 == 0) {
array2[j++] = array1[i];
} else {
array3[k++] = array1[i];
}
}
System.out.println("Original array:\n");
showAray(array1, array1.length);
sort(array2, even);
sort(array3, odd);
for (int i = 1; i < array1.length; i++) {
if (i < odd) {
array1[i] = array3[i];
} else {
array1[i] = array2[(i + 1) - even];
}
}
System.out.println("\nAfter sorting:\n");
showAray(array1, array1.length);
}
}
I know there is a logical error here, but I can't figure out what exactly. Is there any way to change the logic to work with all integers? Thanks.
array1[i] = array2[(i + 1) - even];
EDIT - Here is the stacktrace.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at ary.main(arytest.java:67)
Java Result: 1
Change this
array1[i] = array2[(i + 1) - even];
to
array1[i] = array2[i - odd];
I guess this is what you want
I have been trying to figure out how to properly print the return of my method.
When the program prints the return of my method, I am giving a nullPointerException error on line 45(the line where i am trying to print the method).
*I did try to make the return to the method static so it is accessible.
How do I initialize the "answer" variable so that i can print it outside of my method?
Thank you in advance
import javax.swing.JOptionPane;
public class ListSortMerge {
static int[]answer;
public static void main(String[] args) {
int v1 = 0, v2 = 0;
for(int c = 0; c <= 1; c++) {
String values = JOptionPane.showInputDialog("How many values would you like to store in list "+(c+1)+"?");
if (c==0) {
v1 = Integer.parseInt(values);
}
else{
v2 = Integer.parseInt(values);
}
}
int[] numbers1 = new int[v1];
int[] numbers2 = new int[v2];
merge(numbers1,numbers2);
int i;
System.out.println("\nList 1 before the sort");
System.out.println("--------------------");
for(i = 0; i < (v1); i++) {
System.out.println(numbers1[i]);
}
System.out.println("\nList 2 before the sort");
System.out.println("--------------------");
for(i = 0; i < (v2); i++) {
System.out.println(numbers2[i]);
}
System.out.println("\nList after the sort");
System.out.println("--------------------");
for(i = 0; i < (v1+v2); i++) {
System.out.println(answer[i]);
}
}
public static int[] merge(int[] a, int[] b) {
int[] answer = new int[a.length + b.length];
for(int c = 0; c < (a.length); c++)
{
String aVal1 = JOptionPane.showInputDialog("Input list 1 value " +(c+1));
a[c] = Integer.parseInt(aVal1);
}
for ( int c = 0; c < (b.length); c++){
String aVal2 = JOptionPane.showInputDialog("Input list 2 value " +(c + 1));
b[c] = Integer.parseInt(aVal2);
}
int i = 0, j = 0, k = 0;
while (i < a.length && j < b.length)
{
if (a[i] < b[j])
answer[k++] = a[i++];
else
answer[k++] = b[j++];
}
while (i < a.length)
answer[k++] = a[i++];
while (j < b.length)
answer[k++] = b[j++];
return answer;
}
}
You have two different answer variables: one is a local variable in the merge function and another is a static field in the class. You never initialize the second one.