How to implement merge sort without recursion - java

The arrays are always the size of powers of 2, and it can't be recursive.
If I've made any errors in asking my question this is my first time asking a question. Bear with me please.
The plan is to place markers in powers of two then loop through and place the ordered numbers into an array then putting them back in the array. Then should be placed into the original array in the groups that they were placed split into. Gradually getting bigger until the whole array is sorted.
public static void MergeSortNonRec(long[] a) {
//======================
//FILL IN YOUR CODE HERE
//======================
System.out.println(a.length); // print statement
if (a == null)
return;
int subArray1 = 0;
int subArray2 = 1;
int increment = 0;
int swapCounter = 0;
for (int i = 1; i <= a.length; i *= 2) {
// this loop determines the current size of the sub array
increment = i;
subArray1 = 0;
subArray2 = 0;
swapCounter = 0;
while (subArray2 <= a.length) {
// this will loop until we reach the end of the array
subArray2 += increment;
long[] spareArray = new long[2 * i];
swapCounter = 0;
while (swapCounter <= spareArray.length) {
System.out.println(subArray1 + " " + subArray2); // print statement
if (a[subArray1] < a[subArray2]) {
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray1++;
} else
if (a[subArray1] > a[subArray2]) {
spareArray[swapCounter] = a[subArray2];
swapCounter++;
subArray2++;
} else
if (a[subArray1] == a[subArray2]) {
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray1++;
System.out.println(swapCounter + " " + subArray1); // print statement
spareArray[swapCounter] = a[subArray1];
swapCounter++;
subArray2++;
}
} // this creates an array of the ordered elements
while (swapCounter == spareArray.length) {
subArray1 -= swapCounter / 2;
subArray2 -= swapCounter / 2;
// now the sub array pointers are back to the values they started at
int spareArrayPointer = 0;
for (; subArray1 <= subArray2; subArray1++) {
a[subArray1] = spareArray[spareArrayPointer];
spareArrayPointer++;
} // this places the values in the spare array into the original array
subArray1 -= spareArrayPointer;
spareArrayPointer = 0;
// takes the first pointer back to where it started
}
subArray1 += increment;
subArray2 += increment + increment;
} // end subArray2 <= a.length loop
} // end 2*i loop
} //MergeSortNonRec()

A non-recursive implementation of merge sort could still be based on top down merge sort, using a stack to push and pop pairs of indexes.
A more common implementation of non-recursive merge sort is bottom up, where an array of n elements is treated as n "sorted" runs of size 1 (since their size is 1, they can be considered sorted), then for each merge "pass", merge even and odd runs, which doubles the run size on each pass. Repeat until run size >= array size.
Wiki example. This example could be optimized by swapping A and B after each pass to change the direction of merge with each pass and avoid the copy back except for the lass pass (or determine number of passes in advance, and swap in place to start with run size = 2 before doing the merge passes).
https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation

Related

Trying to create a array with the intersection of two arrays but fails at creating array with the proper structure

So, I am trying to create 2 randomly generated arrays,(a, and b, each with 10 unique whole numbers from 0 to 20), and then creating 2 arrays with the info of the last two. One containing the numbers that appear in both a and b, and another with the numbers that are unique to a and to b. The arrays must be listed in a "a -> [1, 2, 3,...]" format. At the moment I only know how to generate the 2 arrays, and am currently at the Intersection part. The problem is, that I can create a array with the correct list of numbers, but it will have the same length of the other two, and the spaces where it shouldn't have anything, it will be filled with 0s when its supposed to create a smaller array with only the right numbers.
package tps.tp1.pack2Arrays;
public class P02ArraysExtractUniqsAndReps {
public static void main(String[] args) {
int nbr = 10;
int min = 0;
int max = 20;
generateArray(nbr, min, max);
System.out.println();
}
public static int[] generateArray(int nbr, int min, int max) {
int[] a = new int[nbr];
int[] b = new int[nbr];
int[] s = new int[nbr];
s[0] = 0;
for (int i = 0; i < a.length; i++) {
a[i] = (int) (Math.random() * (max - min));
b[i] = (int) (Math.random() * (max - min));
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
i--;
}
if (b[i] == b[j]) {
i--;
}
}
}
System.out.println("a - > " + Arrays.toString(a));
System.out.println("b - > " + Arrays.toString(b));
for (int k = 0; k < a.length; k++) {
for (int l = 0; l < b.length; l++) {
if (a[k] == b[l]) {
s[l] = b[l];
}else {
}
}
}
System.out.println("(a ∪ (b/(a ∩ b)) - > " + Arrays.toString(s));
return null;
}
public static boolean hasValue(int[] array, int value) {
for (int i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
}
Is there any way to create the array without the incorrect 0s? (I say incorrect because it is possible to have 0 in both a and b).
Any help/clarification is appreciated.
First, allocate an array large enough to hold the intersection. It needs to be no bigger that the smaller of the source arrays.
When you add a value to the intersection array, always add it starting at the beginning of the array. Use a counter to update the next position. This also allows the value 0 to be a valid value.
Then when finished. use Array.copyOf() to copy only the first part of the array to itself, thus removing the empty (unfilled 0 value) spaces. This works as follow assuming count is the index you have been using to add to the array: Assume count = 3
int[] inter = {1,2,3,0,0,0,0};
inter = Arrays.copyOf(inter, count);
System.out.println(Arrays.toString(inter);
prints
[1,2,3]
Here is an approach using a List
int[] b = {4,3,1,2,5,0,2};
int [] a = {3,5,2,3,7,8,2,0,9,10};
Add one of the arrays to the list.
List<Integer> list = new ArrayList<>();
for(int i : a) {
list.add(i);
}
Allocate the intersection array with count used as the next location. It doesn't matter which array's length you use.
int count = 0;
int [] intersection = new int[a.length];
Now simply iterate thru the other array.
if the list contains the value, add it to the intersection array.
then remove it from the list and increment count. NOTE - The removed value must be converted to an Integer object, otherwise, if a simple int value, it would be interpreted as an index and the value at that index would be removed and not the actual value itself (or an Exception might be thrown).
once finished the intersection array will have the values and probably unseen zeroes at the end.
for(int i = 0; i < b.length; i++) {
int val = b[i];
if (list.contains(val)) {
intersection[count++] = val;
list.remove(Integer.valueOf(val));
}
}
To shorten the array, use the copy method mentioned above.
intersection = Arrays.copyOf(intersection, count);
System.out.println(Arrays.toString(intersection));
prints
[3, 2, 5, 0, 2]
Note that it does not matter which array is which. If you reverse the arrays for a and b above, the same intersection will result, albeit in a different order.
The first thing I notice is that you are declaring your intersection array at the top of the method.
int[] s = new int[nbr];
You are declaring the same amount of space for the array regardless of the amount you actually use.
Method Arrays.toString(int []) will print any uninitialized slots in the array as "0"
There are several different approaches you can take here:
You can delay initializing the array until you have determined the size of the set you are dealing with.
You can transfer your content into another well sized array after figuring out your result set.
You could forego using Array.toString, and build the string up yourself.

Raman Spectrum processing in Java

I have 2D array of type doubles as spectral data in text file. I have to find peaks in the spectrum. I am using Binary Search to find peaks in the array, but I am getting false peaks also. How can I filter the result I am getting. If anybody know about this please help me
Here is the code which I am using
static ArrayList < Double > nPeaks(double[] array, int range) {
if (array == null) {
System.out.println("Error");
}
double result = 0, l, r;
double[] peaks = null;
// Check main body
for (int i = 0; i < array.length; i++) {
boolean isPeak = true;
// Check from left to right
l = Math.max(0, i - range);
r = Math.min(array.length - 1, i + range);
for (int j = (int) l; j <= r; j++) {
// Skip if we are on current
if (i == j) {
continue;
}
if (array[i] < array[j]) {
isPeak = false;
break;
}
}
if (isPeak) {
//System.out.println("Peak at " + i + " = " + array[i]);
peaklist.add(array[i]);
result++;
i += range;
}
}
return peaklist;
}
Your question is not clear to me. I assume you are generating the max to min order of input array. If yes, you are trying to create a sorted array(descending order).
Simply sort the array in descending order. That will have result like
peak1, peak2, peak3...peakn
where,
peak1 - is max value
peakn - is min value
One of the way to find peaks in spectrum is calculating the disspersion of whole spectrum and then devile it by 3*sigma and take floor funstion. After it you shold "see" only peaks and each place higher than 1 shold be a peak

An algorithm where I find the min and max element value and then do it again after removing those elements

I have the methods to find the smallest and largest value, and also to place them where they need to be. I also have a method to call those methods, and shrink to a subarray. The problem is, even though it is sorting, I can't print the array once I've moved into the subarray. Please help, there has to be a better way and I've banged my head against the wall for a while now.
package mySort;
import java.util.Arrays;
public class MyAlg {
public static int findSmall(int[] input){
int sm = input[0];
for(int i = 0; i <= input.length - 1; i++){
if(sm < input[i])
sm = input[i];
}
input[0] = sm;
return sm;
}
public static int findLarge(int[] input){
int lg = input[input.length -1];
for(int i = 0; i <= input.length - 1; i++){
if(input[i] > lg)
lg = input[i];
}
input[input.length -1] = lg;
return lg;
}
public static int[] sort(int[] input){
findSmall(input);
findLarge(input);
for(int i = 0; i<= (input.length - 1) / 2; i++){
int[] tmp = Arrays.copyOfRange(input, i + 1, input.length - 2 );
findSmall(tmp);
findLarge(tmp);
}
}
}
I am not sure if you are required to use an array or not, but if you are free to use whatever data structure you like I would recommend a TreeSet. This data structure implements SortedSet which means as the objects are added they are sorted already for you. Then you can use methods such as
first() - to return the lowest value
last() - to return the highest value
Then you could remove those highest and lowest elements or use these methods after that
ceiling(int) - highest number lower than given int
floor(int) - smallest number higher than given int
Lmk if you need more help or just need an implementation for an array.
Unfortunately your code is quite flawed, so I just rewrote everything. The below code will sort any int[] by placing the smallest int in the input array in the left most unfilled position of a new array and placing the biggest in the right most unfilled position of a new array, until the new array is a sorted version of the input array. Enjoy
private static int[] sort(int[] input) {
//create an empty array the same size as input
int[] sorted = new int[input.length];
//create another empty array the same size as input
int[] temp = new int[input.length];
// copy input into temp
for (int i = 0; i <= (input.length - 1); i++) {
temp[i] = input[i];
}
//create variables to tell where to put big and small
//in the sorted array
int leftIndex = 0;
int rightIndex = sorted.length - 1;
//create variables to hold the biggest and smallest values in
//input. For now we'll give them the values of the first element
//in input, they'll change
int big = input[0];
int small = input[0];
// sort
//sort the array as you described
while (temp.length != 0) {
//find the biggest and smallest value in temp
big = findBig(temp);
small = findSmall(temp);
//place the biggest at the end of the sorted array
//and place the smallest at the beginning of the sorted array
sorted[leftIndex] = small;
sorted[rightIndex] = big;
//move the left index of the sorted array up, so we don't over write
//the element we put in on the next iteration, same for the right index to,
//but down
leftIndex++;
rightIndex--;
if(temp.length != 1){
//remove the biggest and smallest values from the temp array
temp = removeElement(temp, big);
temp = removeElement(temp, small);
}else{
//only remove one element in the event the array size is odd
//also not at this point leftIndex == rightIndex as it will be the last
//element
temp = removeElement(temp, big);
}
//repeat, until the temp array is empty
}
// print out the content of the sorted array
for (int i = 0; i <= (sorted.length - 1); i++) {
System.out.println("Index " + i + ": " + sorted[i]);
}
//return the sorted array
return sorted;
}
//find the smallest number in an int array and return it's value
private static int findSmall(int[] input) {
int smallest = input[0];
for (int i = 0; i <= (input.length - 1); i++) {
if (smallest > input[i]) {
smallest = input[i];
}
}
return smallest;
}
//find the biggest value in an int array and return it's value
private static int findBig(int[] input) {
int biggest = input[0];
for (int i = 0; i <= (input.length - 1); i++) {
if (biggest < input[i]) {
biggest = input[i];
}
}
return biggest;
}
//remove an element from an int array, based on it's value
private static int[] removeElement(int[] input, int elementValue) {
//create a temp array of size input - 1, because there will be one less element
int[] temp = new int[input.length - 1];
//create variable to tell which index to remove, set to 0 to start
//will change unless it is right
int indexToRemove = 0;
//find out what the index of the element you want to remove is
for (int i = 0; i <= (input.length - 1); i++) {
if (input[i] == elementValue) {
//assign the value to
indexToRemove = i;
break;
}
}
//variable that says if we've hit the index we want to remove
boolean removeFound = false;
for (int i = 0; i <= (input.length - 1); i++) {
//check if we are at the index we want to remove
if (indexToRemove == i) {
//if we are say so
removeFound = true;
}
//done if we aren't at the index we want to remove
if (i != indexToRemove && removeFound == false) {
//copy input to temp as normal
temp[i] = input[i];
}
//done if we've hit the index we want to remove
if (i != indexToRemove && removeFound == true) {
//note the -1, as we've skipped one and need the to decrement
//note input isn't decremented, as we need the value as normal
//note we skipped the element we wanted to delete
temp[i - 1] = input[i];
}
}
//return the modified array that doesn't contain the element we removed
//and it is 1 index smaller than the input array
return temp;
}
}
Also, I'd place all of these methods into a class Sort, but I wrote it in this way to mimic the way you wrote your code to a certain extent. This would require you to create a getSorted method, and I'd also change the sort method to a constructor if it was placed in a class Sort.
I have written an algorithm to solve your this problem. Using divide and conquer we can solve this problem effectively. Comparing each value to every one the smallest and the largest value can be found. After cutting off 2 values the first one(smallest) and the last one (largest) the new unsorted array will be processed with the same algorithm to find the smallest and largest value.
You can see my algorithm in [GitHub] (https://github.com/jabedhossain/SortingProblem/)
Although its written in C++, the comments should be enough to lead you through.

Averaging array values not coming out as expected, gives out of place value instead of correct one

I'm writing a program for a class at school, and when the independents couldn't help, I turn to you...
I encounter my issue when I attempt to find the average - the variables either don't add correctly or they don't divide correctly. For example, an input of [4], [2], [4], [2], will give me 7.0, when it should be 3.0. Similarly, [2], [2], [4], [4], will give 2.0.
As far as I'm aware, the rest of the code functions exactly as it should. I'm including only what should effect it, but I can post the rest if required.
public class ArrayFunctions
{
String elementNumber =
JOptionPane.showInputDialog("How many elements do you want?");
int number = Integer.parseInt(elementNumber);
//assigns how many elements are in the array, based on user input
int[] min_array = new int[number];
int recalculate = 0;
public void arrayValues()
{
for (int i = 1; i < (number + 1); i++)
{
String elementInfo =
JOptionPane.showInputDialog("Input value for element " + i);
int element = Integer.parseInt(elementInfo);
//assigns values for elements, based on user input
min_array[(i - 1)] = element;
}
System.out.println('\u000C'); /*using BlueJ, this clears the console*/
for (int i = 1; i < (number + 1); i++)
{
System.out.println(min_array[(i - 1)]);
}
//prints the values of the elements in the array
}
...
public double avg()
{
for (int i = 1; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[(i - 1)]);
}
//should add together the values of all the elements
//this may be where it stops working as intended
double array_avg = (recalculate / min_array.length);
return array_avg;
//should divide the sum of all the elements by how many elements there are
//this is the other place where it might stop working.
}
Again, I can post more code if required. Sorry about bad/lacking comments and poor structure at times, I need to get this written, because I've a due date for this. :/
for (int i = 1; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[(i - 1)]);
}
This loop is going between index 0 (1 - 1) and index min_array.length - 2 due to your boolean condition in the for loop, stating that it should go while i is LESS than the array's length, and then also subtracting it by 1 in the code.
A possible solution would be to simply go until it's less than OR equal to the size, or simply start your loop at 0 and stop the (i - 1) stuff in the average calculation.
for (int i = 0; i < min_array.length; i++)
{
recalculate += min_array[i];
}
Also, on a side note, you're basically making that same mistake in the GUI stuff as well above; I've corrected it (as well as kept your methodology of using 1-based indexing for asking the user to fill in values, rather than 0-based indexing)
for (int i = 0; i < number; i++){
String elementInfo =
JOptionPane.showInputDialog("Input value for element " + (i + 1));
int element = Integer.parseInt(elementInfo);
min_array[i] = element;
}
System.out.println('\u000C'); /*using BlueJ, this clears the console*/
for (int i = 0; i < number; i++){
System.out.println(min_array[i]);
}
I see that you're going from index 0 to index array.length - 2, instead of -1. That's the problem. I hope this helps
public double avg()
{
for (int i = 0; i < (min_array.length); i++)
{
recalculate = (recalculate + min_array[i]);
}
//should add together the values of all the elements
//this may be where it stops working as intended
double array_avg = (recalculate / min_array.length);
return array_avg;
//should divide the sum of all the elements by how many elements there are
//this is the other place where it might stop working.
}
Also always start a for loop with i=0 for counting purposes

Perfect shuffle algorithm implementation error

Is this code correct for perfect shuffle algorithm ? I'm always trying to generate a number from 0 to n and swapping the number with the last element in the array thereby reducing the range of n. However when the n=0, I get an exception. How do I deal with this case ?
int [] array ={1,2,3,4,5};
Random random = new Random();
int n=array.length;
while(n--!=0)
{
int number = random.nextInt(n);
int temp = array[n];
array[n] = array[number];
array[number] = temp;
}
EDIT: if I change it to --n >0 then it works correctly but am I implementing the shuffling algorithm correctly in that case because I never do anything for n=0 ?
In your code segment
while(n--!=0)
if n is 1, it will become 0 and `random.nextInt(0)` will return an error.
Refer this link
I don't think nextInt works if you pass an argument of 0.
The best way to shuffle is by using the Fisher Yates algorithm. It's fast, works in-place, and is unbiased:
int [] array = {1,2,3,4,5};
Shuffle(array, new Random());
// Fisher Yates shuffle - see http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
void Shuffle(int[] array, Random RNG)
{
for (int i = array.length - 1; i >= 1; i -= 1)
{
// get integer in range of j >= 0 && j < i + 1
int j = RNG.nextInt(i + 1);
//assert(j >= 0 && j <= i);
if (i != j)
{
// only swap if i and j are different
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}

Categories