Java - mergeSort using recursion - java

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.

Related

How to count the number of swaps that occur in a merge sort - Java

I have been working on developing a merge sort algorithm. One of the things I need to figure out is how many swaps are occurring during the algorithm. My code is as follows:
int[] MergeSort(int[] sortArray, int size) {
//Base case
if (size < 2) {
return sortArray;
}
//Finding the middle of the input array and splitting it into two new arrays based on that middle value
int middle = size / 2;
int[] leftArray = new int[middle];
int[] rightArray = new int[size - middle];
//Copy data from the input array to the new arrays
for (int i = 0; i < middle; i++) {
leftArray[i] = sortArray[i];
}
for (int j = middle; j < size; j++) {
rightArray[j - middle] = sortArray[j];
}
//Recursively call the mergesort until the size of the array on each side is one
MergeSort(leftArray, middle);
MergeSort(rightArray, size - middle);
//Stack will recursively merge all of the arrays back together in numerical order
merge(sortArray, leftArray, rightArray, middle, size - middle);
//Return the sorted array (the last return will be what the test class gets)
return sortArray;
}
private void merge(int[] sortArray, int[] leftArray, int[] rightArray, int left, int right) {
//These will be our loop counters that will indicate if we are getting close to the end of the arrays
//(the ends being given by left and right)
int leftCounter = 0;
int rightCounter = 0;
int sortCounter = 0;
//
while (leftCounter < left && rightCounter < right) {
if (leftArray[leftCounter] <= rightArray[rightCounter]) {
sortArray[sortCounter++] = leftArray[leftCounter++];
} else {
sortArray[sortCounter++] = rightArray[rightCounter++];
System.out.println("flag");
}
comparisons++;
}
while (leftCounter < left) {
sortArray[sortCounter++] = leftArray[leftCounter++];
}
while (rightCounter < right) {
sortArray[sortCounter++] = rightArray[rightCounter++];
}
}
The problem I am running into is that for some reason the else branch containing the System.out.println("flag") line is never being run. Every example I have seen of counting the swaps in a merge sort has incremented the swaps in that branch.
All of that said, the algorithm works - if I give it an array it will sort the array properly (these are arrays containing randomly generated numbers). It simply is not accessing that branch so I do not know where to increment the swaps. The best assistance I could receive would be information on where and how I need to increment the swaps.

sort array using recursive method

I am working on trying to write a program where a user will enter 6 strings and then it will sort the array in reverse alphabetical order using a recursive method. This is one concept I do not understand despite multiple videos, readings and attempts. Any support and insight is greatly appreciated. Thank you.
import java.util.Arrays;
import java.util.Scanner;
public class SRecusion {
public static void sort2 (String[] sort2) {
int i;
int min = 0;
int max;
for (i = 0; i <sort2.length -1; i++) {
if (sort2[i].charAt(0)> sort2[i=1].charAt(0)) {
sort2[i] = sort2[min];
}
else {
min = (sort2(sort2[i-1]));
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String [] test = new String[6];
Scanner scnr = new Scanner(System.in);
String userEntry = "";
for(int i = 0; i <= test.length - 1; i++) {
System.out.println("Please enter a word:");
test[i] = scnr.nextLine();
}
sort2(test);
System.out.println("your list is" + Arrays.asList(test));
System.out.println();
}
}
Sorting is a pretty broad topic as there are many different sorting methods (quicksort, merge sort, etc.) However, a pretty basic and simple sorting method is bubble sort. Although it isn't the fastest one, it's pretty easy to understand and code using recursion.
Essentially, bubble sort with iterate through the elements in pairs of 2 and swap the two elements if they're in the wrong order.
For example, let's sort (3, 2, 5, 4, 1) using bubble sort.
(2, 3, 5, 4, 1) First, it'll look at the first two elements swap them if needed. Since 3 is greater than 2, it'll swap them.
(2, 3, 5, 4, 1) Next, it'll look at 3 and 5. Since 3 is less than 5, there is no need to swap
(2, 3, 4, 5, 1) It now looks at 5 and 4 and swaps them.
(2, 3, 4, 1, 5) Finally, it looks at 5 and 1 and swaps them.
Now start from the beginning and repeat the whole process. The sorting ends if exactly 0 swaps are made during an iteration.
If you're still a bit confused, try watching a tutorial on bubble sort or visit this link.
So from what I was asking above as to why you need a recursive sorting algorithm Here it goes I will try to explain how recursive sorting works. It took my some time to figure it out as I am sure it does for most people who first come in contact with it.
public static void Qsort(int[] array, int start, int end)
{
//find the current center of the whole or parital array part I am working on.
int center = (start+end)/2;
///System.out.println("\n This is the center : " + center);
int pivot, i, pivotplace;
i = 0;
pivot = 0;
pivotplace = 0;
//if start = end then we are at a single element. just return to the previous iterative call.
if(start == end)
{
// System.out.println("\n Inside base case return :");
return;
}
//find the pivot value we are using. using a 3 prong selection we are assured to at least get some type of median value and avoid the N^2 worst case.
pivot = getpivot(array[start], array[center], array[end]); //gets median value of start, center and end values in the array.
// System.out.println("\n pivotvalue is : " + pivot);
//find where the current pivot is located and swap it with the last element in the current portion of the array.
if(array[start] == pivot)
{
//System.out.print("\n Inside pivot at start");
swap(array, start, end);
}
else
{
if(array[center] == pivot)
{
//System.out.print("\n Inside pivot at center");
swap(array, center, end);
}
}
//due to iteration the pivot place needs to start at the passed in value of 'start' and not 0.
pivotplace = start;
//due to iteration the loop needs to go from the passed in value of start and not 0 and needs to go
//until it reaches the end value passed in.
for(i = start; i < end; i++)
{
//if the current slot of the array is less than then pivot swap it with the current pivotplace holder
//since the pivotplace keeps getting iterated up be each swap the final place of pivot place
//is where the pivot will actually be swapped back to after the loop cpompletes.
if(array[i] < pivot)
{
//System.out.print("\n Swapping");
swap(array, i, pivotplace);
pivotplace++;
}
}
//loop is finished, swap the pivot into the spot it belongs in.
swap(array, pivotplace, end);
//there are 2 cases for recursive iteration.
//The first is from the start to the slot before the pivot
if(start < pivotplace){Qsort(array, start, pivotplace-1);}
//the second is from the slot after the pivot to the end.
if(pivotplace+1 < end){Qsort(array, pivotplace+1, end);}
}
public static int getpivot(int a, int b, int c)
{
if((a > b) && (a < c))
{
return a;
}
if((b > a) && (b < c))
{
return b;
}
return c;
}
public static void swap(int[] array, int posa, int posb)
{
int temp;
temp = array[posa];
array[posa] = array[posb];
array[posb] = temp;
}
This is a basic Quick Sort or recursive sort I wrote this while in programming classes. You will probably not need to use the getpivot code as you are dealing with a small set of strings, but if you do some research you will see using a possible sample of 3 drastically speeds up the recursion due to balanced work load of the recursion tree.
Sort Array using recursion in kotlin
fun main() {
print(sortArray(arrayListOf(1,3,2,6,8,3)))
}
fun sortArray(arr: MutableList<Int>): MutableList<Int>{
if(arr.size==1) {
return arr
}
val lastValue = arr.last()
arr.removeLast()
sortArray(arr)
insert(arr, lastValue)
return arr
}
fun insert (arr: MutableList<Int>, value: Int): MutableList<Int> {
if(arr.size == 0 || arr.last() < value) {
arr.add(value)
return arr
}
val lastValue = arr.last()
arr.removeLast()
insert(arr, value)
arr.add(lastValue)
return arr
}

Java merge sort recursion strangeness

I was doing some review on sorting algorithms since they don't actually come up that often in real life for me, and this one about drove me mad. I've also not done Java in a while so I thought maybe I had forgotten some language esotarica, but I don't think so.
What I found is that success or failure depends on how I make the recursive call to split the array. So, if I use the return value of the split call as a parameter to the merge call, it works. However, if I call split recursively first, then call merge, it fails. However, it seems to me that they should both work. It seems to have something to do with how the stack unwinds, but I can't quite wrap my head around it.
static Comparable[] mergesort(Comparable[] src) {
if (src.length < 2)
return src;
int middle = src.length / 2;
if (src.length % 2 > 0)
middle++;
Comparable[] left = new Comparable[src.length / 2];
Comparable[] right = new Comparable[middle];
System.arraycopy(src, 0, left, 0, left.length);
System.arraycopy(src, src.length / 2, right, 0, right.length);
// THIS DOESN'T WORK, BUT I DON'T KNOW WHY
// mergesort(left);
// mergesort(right);
// return mergearrays(left, right);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// THIS ONE DOES WORK
//
return mergearrays(mergesort(left), mergesort(right));
}
static Comparable[] mergearrays(Comparable[] left, Comparable[] right) {
Comparable[] retval = new Comparable[left.length + right.length];
int i = 0, j = 0, k = 0;
for (; i < left.length && j < right.length;) {
if (left[i].compareTo(right[j]) >= 0) {
retval[k++] = right[j++];
} else
retval[k++] = left[i++];
}
while (k < retval.length) {
if (i < left.length) {
retval[k++] = left[i++];
}
if (j < right.length) {
retval[k++] = right[j++];
}
}
return retval;
}
Your mergearrays method creates a new array in which it stores the merged sorted array. Therefore if you don't use the arrays returned by mergesort(left) and mergesort(right) (which are themselves arrays created by previous calls to mergearrays), you are discarding the sorted arrays and passing unsorted arrays (left and right) to mergearrays.
Therefore this code is wrong:
mergesort(left); // returns a new sorted array which you ignore, doesn't modify left
mergesort(right); // returns a new sorted array which you ignore, doesn't modify right
return mergearrays(left, right); // merges two unsorted arrays, and therefore is wrong
While this code is right:
// merges the two sorted arrays returned by mergesort(left) and mergesort(right)
return mergearrays(mergesort(left), mergesort(right));
Some merge sort implementations perform the merge step on the original array (i.e. they sort the array in place instead of returning a new sorted array), in which case neither the mergearrays method nor the mergesort need to return anything, and the following can work:
mergesort(left);
mergesort(right);
mergearrays(left, right);

Finding the sum of common elements between n number of arrays in java

I have a program that sums the common elements of two arrays. For that I used two for loops and if I have three then I could use three for loops. But how to sum the common elements of n number of arrays where n is coming during run time.
I don't know how to change the number of loops during run time or is there any other relevant concept for this ?
Here is the code I've tried for summing twoarrays:
import java.util.Scanner;
public class Sample {
public static void main(String... args)
{
Scanner sc=new Scanner(System.in);
int arr1[]={1,2,3,4,5},arr2[]={4,5,6,7,8},sum=0;
for (int i=0;i<arr1.length;i++)
{
for (int j=0;j<arr2.length;j++)
{
if (arr1[i]==arr2[j])
{
sum+=(arr1[i]);
}
}
}
}
}
There can be different implementation for that. You can use the following approach. Here is the pseudo code
use a 2D array to store the array. if the number of array is n and size is m then the array will be input[n][m]
Use a ArrayList commonItems to store the common items of. Initiate it with the elements of input[0]
Now iterate through the array for i = 1 to n-1. compare with every input[i], store only the common items of commonItems and input[i] at each step. You can do it by converting the input[i] into a list and by using retainAll method.
At the end of the iteration the commonItem list will contains the common numbers only. Now sum the value of this list.
There is actually a more general method, that also answers the question "how to change the number of loops during run time?".
The general question
We are looking for a way to implement something equivalent to this:
for (i1 = 0; i1 < k1; i1++) {
for (i2 = 0; i2 < k2; i2++) {
for (i3 = 0; i3 < k3; i3++) {
...
for (in = 0; in < kn; in++) {
f(x1[i1], x2[i2], ... xn[in]);
}
...
}
}
}
where, n is given at runtime and f is a function taking a list of n parameters, processing the current n-tuple.
A general solution
There is a general solution, based on the concept of recursion.
This is one implementation that produces the desired behavior:
void process(int idx, int n, int[][] x, int[] k, Object[] ntuple) {
if (idx == n) {
// we have a complete n-tuple,
// with an element from each of the n arrays
f(ntuple);
return;
}
// this is the idx'th "for" statement
for (int i = 0; i < k[idx]; i++) {
ntuple[idx] = x[idx][i];
// with this recursive call we make sure that
// we also generate the rest of the for's
process(idx + 1, n, x, k, ntuple);
}
}
The function assumes that the n arrays are stored in a matrix x, and the first call should look like this:
process(0, n, x, k, new Object[n]);
Practical considerations
The solution above has a high complexity (it is O(k1⋅k2⋅..⋅kn)), but sometimes it is possible to avoid going until the deepest loop.
Indeed, in the specific problem mentioned in this post (which requires summing common elements across all arrays), we can skip generating some tuples e.g. if already x2[i2] ≠ x1[i1].
In the recursive solution, those situations can easily be pruned. The specific code for this problem would probably look like this:
void process(int idx, int n, int[][] x, int[] k, int value) {
if (idx == n) {
// all elements from the current tuple are equal to "value".
// add this to the global "sum" variable
sum += value;
return;
}
for (int i = 0; i < k[idx]; i++) {
if (idx == 0) {
// this is the outer "for", set the new value
value = x[0][i];
} else {
// check if the current element from the idx'th for
// has the same value as all previous elements
if (x[idx][i] == value) {
process(idx + 1, n, x, k, value);
}
}
}
}
Assuming that the index of the element is not important: a[1] = 2 and a[5] = 2, you only need two nested loops.
First you need to put n-1 arrays in a list of sets. Then loop over nth array and check if each element exists in all of the sets in the list. If it does exist then add to total.

Issue with Modified Bubble Sort Algorithm

Ok I'm trying to write an algorithm for sorting an array, in this case an array of random integers. I know QuickSort or similar would obviously more efficient, but for this assignment I have to basically make a modified version of the inefficient Bubble Sort algorithm.
The idea is to compare integers across a gap. After each pass, the gap is supposed to be cut in half. If value on left is greater than value on right, they are swapped. Execution is supposed to continue until no swaps occurs or gap is 1. I'm usually pretty descent at this sort of thing but it seems that I'm missing something. For some reason the algorithm isn't sorting my arrays.
Here is my code. Maybe someone can see what I'm missing:
public class ShellArray
{
private int capacity;
private int [] randArray;
private static final int RANGE = 200; //Range set to 200 for possible integers.
public ShellArray(int capacity)
{
this.capacity = capacity;
randArray = new int[capacity];
populate(randArray, RANGE, capacity);
}
/**************************************************************************************************************************************************
//
//Populates array with random integers within given range.
//
***************************************************************************************************************************************************/
private static void populate(int [] myArray, int numRange, int extent)
{
Random r = new Random();
for (int i = 0; i < extent; i++)
myArray[i] = (r.nextInt(numRange)+1);
}
/**************************************************************************************************************************************************
//
//The first version of shellSort calls the second version with min value as 0 and max as length of randArray-1. Takes no parameters.
//
***************************************************************************************************************************************************/
public void shellSort()
{
shellSort(0, randArray.length-1);
}
/**************************************************************************************************************************************************
//
// shellSort which takes min and max parameters. Calculates gap at center, across which values are compared. Passes continue until gap size is 1
// and array is sorted.
// Uses boolean sorted to indicate when array is sorted so passes don't continue needelessly after array is sorted. Essentially, if no values
// are swapped after a pass, we know array is sorted and sorted is not set to false.
//
// Outer for loop controls position of final value. Since largest value is bubbled to end, position decreases by 1 after each pass.
// After each pass, size of gap is cut in half, as long as gap is 2 or greater. Otherwise gap would become too small.
// Inner for loop controls the index values to be compared.
// Uses swap method to swap values which are not in the correct order.
// Array is printed after each pass.
//
***************************************************************************************************************************************************/
public void shellSort(int min, int max)
{
String result;
int gap;
int j = 0;
int size = randArray.length-1;
boolean swapped;
for(gap = size/2; gap <= 0; gap = gap/2)
{
swapped = true;
while (swapped)
{
swapped = false;
int comp;
for(comp = 0; comp+gap <= size; comp++)
{
if (randArray[comp] > randArray[comp+gap])
{
swap(comp, comp+gap);
swapped = true; //swapped set to true if any element is swapped with another.
}
else
swapped = false;
}
}
result = "";
for(int y = 0; y < randArray.length; y++)
{
result += randArray[y] + " ";
j++;
}
System.out.println("Pass " +j+": " +result+"\n");
}
}
/**************************************************************************************************************************************************
//
// Swaps two values in the array.
//
***************************************************************************************************************************************************/
private void swap(int index1, int index2)
{
int temp = randArray[index1];
randArray[index1] = randArray[index2];
randArray[index2] = temp;
}
public String toString()
{
String result = "";
for(int y = 0; y < randArray.length; y++)
result += randArray[y] +" ";
return result;
}
}
You haven't provided the details of your assignment, but the idea of a sort along these lines is that the final stage (i.e. with gap == 1) is a bona fide standard sort all on its own -- in this case, I guess a bubble sort -- and the prior stages pre-treat the input so that the efficiency of that final sort is much better than for random input. At least for gap == 1, then, you must repeat the sort loop until there are no swaps.
There are two main variations possible here, and you haven't given us the information to know which you want:
The first variation shrinks the gap after each iteration of the sort loop until it reaches 1, then repeats with that gap until there are no more swaps.
The second variation repeats the sort loop with the same gap until there are no swaps, then shrinks the gap and repeats.
My guess would be that you want the second, as that's the one that is actually a shell sort (of an unusual flavor). Even though it might sound like it would be less efficient than the other, there's a good chance that it's more efficient, because devoting a small amount of additional effort when the gap is large accomplishes larger element movements in fewer steps.

Categories