Java: How to change an Integer array parameter from inside a method - java

I have a programming assignment where I have to make a method that takes in an array that is split up into subarrays, and merge them. My method works fine but the Integer array that is passed in 'a' is only changed from inside the method, and remains unchanged from the outside.
After looking around on google, I have concluded that it is impossible to change an array parameter, but then I thought about Arrays.sort which does end up changing the array parameter from outside of the method.
How do I change the array that is passed in as a parameter so that it stays changed outside of the method?
/**
* Merge three sorted arrays with these ranges [lo..mid1], [mid1+1..mid2], [mid2+1..hi] into one sorted array.
* Array a has the original input and final sorted input.
* Array aux is the auxiliary array.
*/
public static void Merge(Integer[] a, int lo, int mid1, int mid2, int hi, Integer[] aux) {
int[] arr1 = copyArray(a, lo, mid1);
int[] arr2 = copyArray(a, mid1+1, mid2);
int[] arr3 = copyArray(a, mid2+1, hi);
int i = 0, j = 0, k = 0, idx = 0;
while(i < arr1.length-1 || j < arr2.length-1 || k < arr3.length-1) {
// arr1[i] is the smallest
if(arr1[i] <= arr2[j] && arr1[i] <= arr3[k]) {
System.out.println("i is bigger at " + arr1[i]);
aux[idx] = arr1[i];
i++;
}
// arr2[j] is the smallest
else if(arr2[j] <= arr1[i] && arr2[j] <= arr3[k]) {
System.out.println("j is bigger at " + arr2[j]);
aux[idx] = arr2[j];
j++;
}
// arr3[k] is the smallest
else if(arr3[k] <= arr2[j] && arr3[k] <= arr1[i]) {
System.out.println("k is bigger at " + arr3[k]);
aux[idx] = arr3[k];
k++;
}
idx++;
}
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.toString(arr2));
System.out.println(Arrays.toString(arr3));
System.out.println(Arrays.toString(aux));
a = aux;
a[0] = 900;
System.out.println("a from Merge method: " + Arrays.toString(a));
}

You have to iterate over your aux array and assign the value to the 'a' array:
a[i] = aux[i]
Or return your merged array as result.
public static int[] Merge(int[] a, int mid1, ...){
// do something
return a;
}

You can change void to int[][] and then return the arrays
public static int[][] Merge(arguments) {
//Do math
int[][] result = new int[][] {arr1, arr2, arr3};
return result;
}
Then, outside of the method you call It like below:
int[][] integerArray = Merge(arguments);
arr1 = integerArray[0];
arr2 = integerArray[1];
arr3 = integerArray[2];

Related

Why do we use two different loop variables while sorting an array using merge sort?

I was learning to merge sort an integer array, when I noticed that while copying the sorted array elements to the original array, we need two separate loop variables to run simultaneously, while the values at those indices are copied to the original array. Here is the code for reference:
class MergeSort {
public static void sort(int arr[], int si, int ei, int mid) {
int merged[] = new int[ei - si + 1];
int index1 = si; // tracks the first array
int index2 = mid + 1; // tracks the second array
int i = 0;
while (index1 <= mid && index2 <= ei) {
if (arr[index1] <= arr[index2]) {
merged[i++] = arr[index1++];
} else {
merged[i++] = arr[index2++];
}
} // end of while
while (index1 <= mid) {
merged[i++] = arr[index1++];
}
while (index2 <= ei) {
merged[i++] = arr[index2++];
}
// to copy merged[] to arr[]
int j = si;
for (i = 0; i < merged.length; i++, j++) {
arr[j] = merged[i];
}
} // end sort()
public static void divide(int arr[], int si, int ei) {
// base case
if (si >= ei) {
return;
} // end of base case
int mid = si + (ei - si) / 2; // same as (ei-si)/2 but with less space complexity
divide(arr, si, mid);
divide(arr, mid + 1, ei);
sort(arr, si, ei, mid);
} // end of divide
public static void main(String args[]) {
int arr[] = { 1, 8, 0, 7, -4 };
int n = arr.length;
divide(arr, 0, n - 1);
for (int i = 0; i < n; i++) {
System.out.print(arr[i] + " ");
} // end of for
} // end of main
} // end of class
Notice that while copying the values of the array merged[] to the array arr[], we are using two separate variables i and j. I did try using only one loop variable, which went like:
for (int i = 0; i < arr.length; i++) {
arr[i] = merged[i];
}
but received an incorrect output. If anyone knows why we need two separate variables for the operation, please let me know. Thank you :)
You could use a single variable in this final loop, but you must add the offset of the start of the slice in the destination array:
for (int i = 0; i < arr.length; i++) {
arr[si + i] = merged[i];
}

Merge sort recursion trouble

I've been trying to make a merge sort and I got the merging part down, it's just the recursive splitting that I'm having a little trouble with. The left and right lists are getting merged and sorted individually and not carrying over between each recursive pass. I'm not sure what I'm doing wrong with the recursion or how to fix it without scrapping the entire division method.
public static int[] mergeSort(int[] x)
{
divide(x);
return sorted;
}
public static void divide(int[] x)
{
int midP;
if((x.length/2f) == 1.5f) //the left side of the list will always be larger
midP = 2;
else
midP = x.length/2;
if(midP == 0) //if the list contains one number end
return;
System.out.println("mid: " + midP);
int[] left = new int[midP];
int[] right = new int[x.length - midP];
for(int i = 0; i < midP; i++) //fills the left list
left[i] = x[i];
for(int i = midP; i < x.length; i++) //fills the right list
right[i-midP] = x[i];
divide(left);
divide(right);
sorted = merge(left, right);
}
public static int[] merge(int[] x, int[] y)
{
int[] mergedList = new int[x.length + y.length];
int counter = 0, xCounter = 0, yCounter = 0, high = 0;
while(xCounter < x.length && yCounter < y.length)
{
printArray(x);
printArray(y);
System.out.println("checking: " + x[xCounter] + " " + y[yCounter]);
if(x[xCounter] < y[yCounter])
{
mergedList[counter] = x[xCounter];
high = y[yCounter];
if(xCounter != x.length)
xCounter++;
}
else
{
mergedList[counter] = y[yCounter];
high = x[xCounter];
if(yCounter != y.length)
yCounter++;
}
counter++;
}
mergedList[counter] = high;
return mergedList;
}
public static void printArray(int[] x)
{
System.out.print("list: ");
for(int i = 0; i < x.length; i++)
System.out.print(x[i] + " ");
System.out.println();
}
When using recursive methods, it's tricky to use static or instance variables like sorted in this case. What's happening is that sorted gets set and reset over the recursive calls, and it can be difficult to predict what its value will be at any given time. Recursive functions are easier to understand if you only use local variables. So change your divide function so that it returns the sorted array, and use the return value from the recursive calls:
public static int[] divide(int[] x) {
... your existing divide logic ...
int[] leftSorted = divide(left);
int[] rightSorted = divide(right);
return merge(leftSorted, rightSorted);
}
Don't forget to also change the main entry point:
public static int[] mergeSort(int[] x) {
return divide(x);
}
You seem to still have a bug in the merge method:
int[] x = {5, 4, 1, 2, 3};
int[] sorted = mergeSort(x);
results in 1 2 3 4 0

Implementing Merge Sort with Java

I was trying to implement merge sort using java, but it's saying:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at HelloWorld.merge(HelloWorld.java:42)
at HelloWorld.sort(HelloWorld.java:30)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.sort(HelloWorld.java:29)
at HelloWorld.sort(HelloWorld.java:28)
at HelloWorld.main(HelloWorld.java:10)
So I tried to copy the original array into a helper array in the merge subroutine, I think it's the length I use for helper array messed everything up, isn't "r-l+1" the length of the helper array?
If I put 100 as the length of the helper array, the code would work, but obviously it's not going to work when the size of the original array gets larger.
Please help and thanks in advance.
public class HelloWorld{
public static void main(String []args){
HelloWorld ms = new HelloWorld();
int arr[] = new int[]{4,3,0,1,3,2,4,20,13,22,10};
ms.sort(arr, 0, arr.length - 1);
ms.printArr(arr);
}
void printArr(int arr[])
{
int n = arr.length;
for(int i = 0; i<n; i++){
System.out.print(" "+arr[i]);
}
}
void sort(int arr[], int l, int r)
{
if(l<r){
int m = (l+r)/2;
sort(arr, l, m);
sort(arr, m+1, r);
merge(arr, l, m, r);
}
}
void merge(int arr[], int l, int m, int r)
{
//find out helper array length
int helper[] = new int[r-l+1];
// Your code here
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
int i = l;
int k = l;
int j = m+1;
while(i<=m && j<=r){
if(helper[i]<=helper[j]){
arr[k]=helper[i];
i++;
}else{
arr[k]=helper[j];
j++;
}
k++;
}
while(i<=m){
arr[k]=helper[i];
i++;
k++;
}
}
}
If I understand the way you're attempting to implement the MERGE subroutine for your merge sort algorithm correctly, you're copying the relevant portion of the array (from index l, inclusive, to index l, inclusive) into the helper array, then modifying the original array using the data copied into the helper array.
In this case, the helper array should indeed have length r-l+1. However, taking a look at your code for copying the original array portion into the helper array, you're not offsetting your indexes in the for loop. The correct way to do it would be:
int helper[] = new int[r-l+1];
for (int i = l; i <= r; i++){
helper[i-l] = arr[i];
}
Don't forget arrays are zero indexed!
I do however recommend moving on to more modern ways of copying arrays if you absolutely have to copy them. In this case, the most adapted in my opinion would be the system call System.arraycopy(arr, l, helper, 0, r-l+1). If you would like to read more about the different methods of copying an array (completely or partially) in Java, check this answer out.
You create an array with the size r - l + 1
int helper[] = new int[r-l+1];
The merge method will be executed with l = 3, m = 3, r = 4
So the array helper has a size of r - l + 1 = 2 = [0, 0]
Your for loop runs from l..r
for(int i=l; i<=r; i++){
helper[i] = arr[i];
}
And you try to set the value from arr[3] to helper[3] which is not possible because helper.length = 2
That's why the ArrayIndexOutOfBoundsException occurs! You can modfiy the access to the helper index to i - l
void merge(int arr[], int l, int m, int r) {
// find out helper array length
int helper[] = new int[r - l + 1];
// Your code here
System.arraycopy(arr, l, helper, 0, helper.length);
int i = l;
int k = l;
int j = m + 1;
while (i <= m && j <= r) {
if (helper[i - l] <= helper[j - l]) { // <---
arr[k] = helper[i - l]; // <---
i++;
} else {
arr[k] = helper[j - l]; // <---
j++;
}
k++;
}
while (i <= m) {
arr[k] = helper[i - l]; // <---
i++;
k++;
}
}

Subset sum for double data-type?

I have the following code for subset sum which is suitable for integers. How to extend this code to double data type input? for example, how to extend this same code when the input is 1.01,2.65,3.08,4.07,5.12 (say) and output is 15.62 (say).These inputs and out are example even if they vary the code should work.
// A Java program to count all subsets with given sum.
import java.util.ArrayList;
public class subset_sum
{
// dp[i][j] is going to store true if sum j is
// possible with array elements from 0 to i.
static boolean[][] dp;
static void display(ArrayList<Integer> v)
{
System.out.println(v);
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
static void printSubsetsRec(int arr[], int i, int sum,
ArrayList<Integer> p)
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if (i == 0 && sum != 0 && dp[0][sum])
{
p.add(arr[i]);
display(p);
p.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0)
{
display(p);
p.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(p);
printSubsetsRec(arr, i-1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i] && dp[i-1][sum-arr[i]])
{
p.add(arr[i]);
printSubsetsRec(arr, i-1, sum-arr[i], p);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
static void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
dp = new boolean[n][sum + 1];
for (int i=0; i<n; ++i)
{
dp[i][0] = true;
}
// Sum arr[0] can be achieved with single element
if (arr[0] <= sum)
dp[0][arr[0]] = true;
// Fill rest of the entries in dp[][]
for (int i = 1; i < n; ++i)
for (int j = 0; j < sum + 1; ++j)
dp[i][j] = (arr[i] <= j) ? (dp[i-1][j] ||
dp[i-1][j-arr[i]])
: dp[i - 1][j];
if (dp[n-1][sum] == false)
{
System.out.println("There are no subsets with" +
" sum "+ sum);
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
ArrayList<Integer> p = new ArrayList<>();
printSubsetsRec(arr, n-1, sum, p);
}
//Driver Program to test above functions
public static void main(String args[])
{
int arr[] = {1, 2, 3, 4, 5};
int n = arr.length;
int sum = 10;
printAllSubsets(arr, n, sum);
}
}
Output:[4, 3, 2, 1] [5, 3, 2] [5, 4, 1]
I found answer to this question by simply converting double to integer by calculating decimal places and multiply it by 100(say) as the algorithm uses addition this change does not affect final values in that case I divided the final value by 100 to get the result and displayed it in double data type

Java Merge Sorting Compare and Count

I have been having trouble with figuring this problem out. I've added a count and compare to identify how many times my sort actually does something and I believe that I am doing it incorrectly because it is not matching up to my example.
import java.util.Arrays;
public class MergeSort {
/**
* #param args
*/
// Rearranges the elements of a into sorted order using
// the merge sort algorithm (recursive).
static int compCount;
static int swapCount;
public void mergeSort(int[] a, int howMany) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
mergeSort(left,howMany);
mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
merge(a, left, right);
}
swapCount++;
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static void merge(int[] result, int[] left,
int[] right) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
for (int i = 0; i < result.length; i++) {
compCount++;
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
//swapCount++;
} else {
result[i] = right[i2]; // take from right
i2++;
//swapCount++;
}
}
System.out.println("merge sort " + compCount + " " + swapCount);
}
}

Categories

Resources