sort merge code in java needs some clarifications - java

Can you explain some lines below please ( I put ? in front of each line that needed to be explained). Thanks in advance !
I know that :
Merge-sort on an input sequence S with n elements consists of three steps:
Divide: partition S into two sequences S1 and S2 of about n/2 elements each
Recur: recursively sort S1 and S2
Conquer: merge S1 and S2 into a unique sorted sequence
But when I read the code I lost my way, can you just guid me please.
public class MergeSort {
public static int[] mergeSort(int [] list) {
if (list.length <= 1) {
return list;
}
// Split the array in half
int[] first = new int[list.length / 2]; // ok
int[] second = new int[list.length - first.length]; // ?
System.arraycopy(list, 0, first, 0, first.length); // ?
System.arraycopy(list, first.length, second, 0, second.length); // not sure ?
// Sort each half
mergeSort(first); // ok
mergeSort(second); // ok
// Merge the halves together, overwriting the original array
merge(first, second, list); // ok
return list; // ok
}
private static void merge(int[] first, int[] second, int [] result) { // explain in general ?
// Merge both halves into the result array
// Next element to consider in the first array
int iFirst = 0;
// Next element to consider in the second array
int iSecond = 0;
// Next open position in the result
int j = 0;
// As long as neither iFirst nor iSecond is past the end, move the
// smaller element into the result.
while (iFirst < first.length && iSecond < second.length) { // ??!!
if (first[iFirst] < second[iSecond]) {
result[j] = first[iFirst];
iFirst++;
} else {
result[j] = second[iSecond];
iSecond++;
}
j++;
}
// copy what's left
System.arraycopy(first, iFirst, result, j, first.length - iFirst);
System.arraycopy(second, iSecond, result, j, second.length - iSecond);
}
public static void main(String args[]) throws Exception
{
String list="";
int i=0,n=0;
MergeSort s= new MergeSort();
ArrayList<Integer> arrlist=new ArrayList<Integer>();
System.out.println(" ");
System.out.println(" ");
System.out.println("Please enter the list of elements,one element per line");
System.out.println(" write 'STOP' when list is completed ");
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
while(!(list=bf.readLine()).equalsIgnoreCase("stop")){
int intelement=Integer.parseInt(list);
arrlist.add(intelement);
}
int elementlist[] = new int[arrlist.size()];
Iterator<Integer> iter = arrlist.iterator();
for (int j=0;iter.hasNext();j++) {
elementlist[j] = iter.next();
}
elementlist=mergeSort(elementlist); // ?
System.out.println(" ");
System.out.println(" ");
System.out.println(" ");
System.out.println("Values after Merge Sort : ");
for (int j=0;j<elementlist.length;j++) {
System.out.println(elementlist[j]+" ");
}
}
}

In int[] first = new int[list.length / 2]; and int[] second = new int[list.length - first.length]; method is dividing the list into 2 arrays, lets say your list has a length of 5 first will have 2 as its size and 3 for second. In
System.arraycopy(list, 0, first, 0, first.length);
System.arraycopy(list, first.length, second, 0, second.length);
your populating both first and second arrays from your list array( copy list[0],list[1] to first array and list[2],list[3],list[4] to second array).
In private static void merge(int[] first, int[] second, int [] result) you are merging first and second arrays and overwriting the result array
in the while loop you take the first element of first and second arrays and comparing them and move the smallest to result[0] then increment the pointer to arrays accordingly by using if and else statements and now you have the smallest element in both first and second arrays placed in result[0] .
You increment j ,it means in this iteration you will put the second smallest element in result[1] and so on.
In elementlist=mergeSort(elementlist); you are sorting elementlist by invoking your mergeSort(int [] list); method.

Related

Java - mergeSort using recursion

I was going through the below sample program and was trying to understand how the below recursion works, I couldn't understand how the left and the right array elements are sorted, finally merging the two subarrays as below. Any pictorial explanation of the below method would be of great help, as I try to understand the below recursive code.
public static int[] mergeSort(int[] arrayToSort) {
// BASE CASE: arrays with fewer than 2 elements are sorted
if (arrayToSort.length < 2) {
return arrayToSort;
}
// STEP 1: divide the array in half
// we use integer division, so we'll never get a "half index"
int midIndex = arrayToSort.length / 2;
int[] left = Arrays.copyOfRange(arrayToSort, 0, midIndex);
int[] right = Arrays.copyOfRange(arrayToSort, midIndex, arrayToSort.length);
// STEP 2: sort each half
int[] sortedLeft = mergeSort(left);
int[] sortedRight = mergeSort(right);
// STEP 3: merge the sorted halves
int[] sortedArray = new int[arrayToSort.length];
int currentLeftIndex = 0;
int currentRightIndex = 0;
for (int currentSortedIndex = 0; currentSortedIndex < arrayToSort.length;
currentSortedIndex++) {
// sortedLeft's first element comes next
// if it's less than sortedRight's first
// element or if sortedRight is exhausted
if (currentLeftIndex < sortedLeft.length
&& (currentRightIndex >= sortedRight.length
|| sortedLeft[currentLeftIndex] < sortedRight[currentRightIndex])) {
sortedArray[currentSortedIndex] = sortedLeft[currentLeftIndex];
currentLeftIndex++;
} else {
sortedArray[currentSortedIndex] = sortedRight[currentRightIndex];
currentRightIndex++;
}
}
return sortedArray;
}
The sorting is performed in the merging loop:
if the array is very small (0 or 1 element), mergeSort() returns it immediately.
otherwise, it splits the array into 2 subarrays of approximately the same size, left and right, which are sorted by calling the same method recursively:
// STEP 2: sort each half
int[] sortedLeft = mergeSort(left);
int[] sortedRight = mergeSort(right);
the final step iterates over the sorted halves to produce a new sorted array.
The recursive calls complete because they are only performed with sub arrays strictly smaller than the argument array.

What is wrong with my remove method for certain array integers?

I have to create a method that will remove at certain value from an array and create a new array without that certain value. For example, if my array is (0,2,3,5,3) and I want to remove 3, the new array should be (0,2,5). For some reason, it only works for the first two digits.
import java.util.Scanner;
public class removeDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//array of numbers
int array[] = new int[] {0,1,2,3,4,5};
//invokes method and prints result
//System.out.println(remove(3,array));
remove(3,array);
}
//method remove that removes selected number from array
public static int[] remove(int v, int[] in) {
//count variable counts how many non-target numbers
int count = 0;
//for loop that checks if value at certain index is not equal to "v", the target number for removal
for(int k = 0; k < in.length; k++) {
//checks if certain number at certain index of array is not equal to v, or in this case, 3
if(in[k] != v) {
//counter
count++;
}
}
//new array that will stores values except "v"
int copy[] = new int[count];
//prints the length
System.out.println("array length: " + copy.length);
//for loop that checks if number not 3
for(int a = 1; a < in.length;) {
// sets number at certain index of main array into new array
if(in[a] != 3){
copy[a] = in[a];
a++;
System.out.println(copy[0]);
System.out.println(copy[1]);
System.out.println(copy[2]);
System.out.println(copy[3]);
}
else if(in[a] == 3) {
copy[a] = in[a+1];
}
}
//returns new array
return copy;
}
}
As said before, I need the new array to exclude the targeted number for removal.
You need two index variables for making the copy: one runs through the input array (a, as in the original code), and the other tracks your position in the output array (b, new variable). They can not be calculated from each other (they are the same at the beginning, but b can be significantly less than a at the end)
int b = 0;
for(int a = 0; a < in.length; a++) {
if(in[a] != v) {
copy[b] = in[a];
b++;
}
}
Using Java8 and it's streams feature you could do something like :
public static void main(String[] args) {
int[] array = {3236,47,34,34,73,46,3,64,473,4,4,346,4,63,644,4,6,4};
int[] newArray = removeAllOccurencesOf(array, 4);
System.out.println(Arrays.toString(newArray));
}
public static int[] removeAllOccurencesOf(int[] array, int numberToRemove)
{
//stream integers from array, filter the ones that correspond to number to remove, get what's left to new array
int[] newArray = IntStream.of(array).filter(i->i!=numberToRemove).toArray();
return newArray;
}
You can achieve the same result with some code like this:
// Add to params all inputs to remove from array
List<Integer> params = new ArrayList<>();
// Use Integer class instead of int datatype
Integer array[] = new Integer[] {0,1,2,3,4,3};
// Convert array to List class
List<Integer> list = new ArrayList<>(Arrays.asList(array));
// Remove all matches
list.removeAll(params);

How to get a collection of combinations of an Integer arrayList in Java

My goal is to find all possible combinations of items in an ArrayList with a fixed predefined length. For example, if my ArrayList is called arr and contains <1, 2, 3> then the desired output for the predefined size r = 2 will be:
<1,2>
<1,3>
<2,3>
Here is code I found which prints the desired output. My problem is that I need to define a return value type ArrayList which holds the outputs from the method. Besides, my input type is also an ArrayList<Integer>, instead of an Array, which has made it more complicated for me because then I first will need to convert the values to the primitive type int.
import java.io.*;
class Permutation {
/* arr[] ---> Input Array
data[] ---> Temporary array to store current combination
start & end ---> Staring and Ending indexes in arr[]
index ---> Current index in data[]
r ---> Size of a combination to be printed */
static void combinationUtil(int arr[], int data[], int start,
int end, int index, int r)
{
// Current combination is ready to be printed, print it
if (index == r)
{
for (int j=0; j<r; j++)
System.out.print(data[j]+" ");
System.out.println("");
return;
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (int i=start; i<=end && end-i+1 >= r-index; i++)
{
data[index] = arr[i];
combinationUtil(arr, data, i+1, end, index+1, r);
}
}
// The main function that prints all combinations of size r
// in arr[] of size n. This function mainly uses combinationUtil()
static void printCombination(int arr[], int n, int r)
{
// A temporary array to store all combination one by one
int data[]=new int[r];
// Print all combination using temprary array 'data[]'
combinationUtil(arr, data, 0, n-1, 0, r);
}
/*Driver function to check for above function*/
public static void main (String[] args) {
int arr[] = {1, 2, 3, 4, 5};
int r = 3;
int n = arr.length;
printCombination(arr, n, r);
}
}
/* This code is contributed by Devesh Agrawal */
ArrayList is backed up by an array internally so translating the current array based implementation to ArrayList should be reasonable. In arrays you use the [] operator to index an element in the array, and the parallel operations using ArrayList are get and set. Also you might want to read on Autoboxing and Unboxing. A possible implementation using Lists:
static void combinationUtil(List<Integer> list, List<Integer> data, int start, int end, int index, int r) {
// Current combination is ready to be printed, print it
if (index == r) {
for (int j = 0; j < r; j++)
System.out.print(data.get(j) + " ");
System.out.println("");
return;
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (int i = start; i <= end && end - i + 1 >= r - index; i++) {
data.set(index, list.get(i));
combinationUtil(list, data, i + 1, end, index + 1, r);
}
}
// The main function that prints all combinations of size r
// in list of size n. This function mainly uses combinationUtil()
static void printCombination(List<Integer> list, int n, int r) {
// A temporary array to store all combination one by one
List<Integer> data = new ArrayList<>(Collections.nCopies(r, 0));
// Print all combination using temporary array 'data'
combinationUtil(list, data, 0, n - 1, 0, r);
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int r = 3;
int n = list.size();
printCombination(list, n, r);
}

Getting all combinations from a list using recusion, including combinations that use the same number

I have a list of numbers: [10, 13, 15]. I am trying to find the combinations of numbers in the list that add up to or are less than the target of 28.
Currently I have a recursive method:
public void combinations(ArrayList<Integer>data,int fromIndex, int endIndex)
{
int sum = 0;
int target = 28;
ArrayList<Integer>results = new ArrayList<Integer>();
if(fromIndex == endIndex)
{
return;
}
for(int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++)
{
if(sum + data.get(currentIndex) <= target)
{
results.add(data.get(currentIndex));
sum +=data.get(currentIndex);
}
}
System.out.println(results);
combinations(data, fromIndex + 1, endIndex);
}
Currently this outputs:
[10, 13],[13, 15],[15] which are correct and I understand why I am getting these solutions as my recursive method has a +1. However other solutions such as [10],[13],[10,10] ect are not included and I was wondering how I would go about implementing this, would I need to change my increments in my recursive method?
public static void combinations(ArrayList<Integer> arr, ArrayList<ArrayList<Integer>> ans, int startIndex, int endIndex, int sum) {
if(startIndex > endIndex) {
for(ArrayList<Integer> x : ans) {
System.out.println(x);
}
return;
}
ArrayList<Integer> newTemp;
ArrayList<ArrayList<Integer>> newAns = new ArrayList<ArrayList<Integer>>();
for(ArrayList<Integer> x : ans) {
newAns.add(x);
}
for(ArrayList<Integer> x : ans) {
int s = 0;
newTemp = new ArrayList<Integer>();
for(Integer v : x) {
newTemp.add(v);
s+=v;
}
if(s + arr.get(startIndex) <= sum) {
newTemp.add(arr.get(startIndex));
newAns.add(newTemp);
}
}
if(arr.get(startIndex) <= sum ) {
newTemp = new ArrayList<Integer>();
newTemp.add(arr.get(startIndex));
newAns.add(newTemp);
}
combinations(arr,newAns, startIndex+1, endIndex, sum);
}
I have to rewrite your code as I was unable to think through your code.
Secondly, I have to make a newArrayList all time to avoid ConcurrentModificationException which I have faced the first time and will overcome later after gaining some knowledge about it.
Now, this method should be called as
public static void main (String[] args) {
ArrayList<Integer> arr = new ArrayList<Integer>();
arr.add(10);
arr.add(15);
arr.add(13);
arr.add(-5);
arr.add(28);
combinations(arr, new ArrayList<ArrayList<Integer>>(), 0, 4, 28);
}
Explanation: I have generalized your question's answer to fit any sum in int range.
I have made ArrayList of ArrayList which will print all the combinations at the base case.
I have first added an ArrayList containing single element i.e current element if the current element is the <= sum.
Then with all remaining ArrayList, I have calculated the sum of each and then check whether adding the current element into the previous ArrayList holds the above condition.
At the same time I have made new ArrayList and copied all elements while I was calculating the sum of each ArrayList and then if the second case holds good then I added the current element into temp ArrayList and then added the temp ArrayList to the answer ArrayList of ArrayLists.
Then I called the recursion by incrementing the startIndex by 1.

Insert element in array - JAVA

WHY there is an ArrayIndexOutOfBounds Exception ..Please Clarify :)
I have tried changing the size of the array but still I am unable to create successful program
import java.util.Scanner;
class insert
{
public static void main(String[]args) throws Exception
{
Scanner sc = new Scanner(System.in);
int a[]= new int[5];
int i;
for(i=0;i<a.length-1;i++)
{
System.out.println("Enter the Element : ");
a[i]=sc.nextInt();
}
System.out.println("Enter the location for insertion : ");
int loc = sc.nextInt();
System.out.println("Enter the value for location : " +loc+" is");
int value = sc.nextInt();
for(i=a.length-1;i>loc;i--)
{
a[i+1]=a[i];
}
a[loc-1] = value;
System.out.println("New Array is : ");
for (i=0;i<=a.length-1;i++)
{
System.out.println(a[i]);
}
}
}strong text
In this part:
for(i=a.length-1;i>loc;i--)
{
a[i+1]=a[i];
}
On the first iteration, a[i+1] is the same as a[a.length], but the last element in array is a[a.length-1], becausefirst element is a[0] and last one is a[length-1], in total a.length number of elements. So modify your loop accordingly.
One side note, when you define a size of an array, you cannot change it. Size is immutable. So you cannot insert an element and try to shift all the elements, because you need to increase the size with 1, which is not possible.
For this scenario, use ArrayList<Integer>>. ArrayList size increases as you add new elements
It is this for loop throwing the RuntimeException
for(i=a.length-1;i>loc;i--) {
a[i+1]=a[i];
}
You are trying to set the value of i + 1 element of the array, which is not existing.
/* Inserting an element in an array using its Index */
import java.util.*;
public class HelloWorld{
public static void main(String []args){
int[] a = {1,2,3,4,5};
int[] b = new int[a.length + 1];
int index = 2;
int element = 100;
System.out.println("The original array is: "+ Arrays.toString(a));
// In this for loop we iterate the original array from the front
for (int i = 0; i<index; i++){
b[i] = a[i];
}
// Here we insert the element at the desired index
b[index] = element;
// In this for loop we start iterating the original array from back.
for (int i = a.length; i>index; i--){
b[i] = a[i-1];
// b[3] = a[2];
}
System.out.println("The new Array is: " + Arrays.toString(b));
}
}
Output:
The original array is: [1, 2, 3, 4, 5]
The new Array is: [1, 2, 100, 3, 4, 5]

Categories