Perfect shuffle algorithm implementation error - java

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;
}
}
}

Related

Creating a method that merges 2 arrays into one sorted array in ascending order in Java

For part of an assignment, I have to create a method that merges 2 arrays into one sorted array in ascending order. I have most of it done, but I am getting a bug that replaces the last element in the array with 0. Has anyone ever run into this problem and know a solution? Heres my code:
public static OrderedArray merge(OrderedArray src1, OrderedArray src2) {
int numLength1 = src1.array.length;
int numLength2 = src2.array.length;
//combined array lengths
int myLength = (numLength1 + numLength2);
// System.out.println(myLength);
OrderedArray mergedArr = new OrderedArray(myLength);
//new array
long[] merged = new long[myLength];
//loop to sort array
int i = 0;
int j = 0;
int k = 0;
while (k < src1.array.length + src2.array.length - 1) {
if(src1.array[i] < src2.array[j]) {
merged[k] = src1.array[i];
i++;
}
else {
merged[k] = src2.array[j];
j++;
}
k++;
}
//loop to print result
for(int x = 0; x < myLength; x++) {
System.out.println(merged[x]);
}
return mergedArr;
}
public static void main(String[] args) {
int maxSize = 100; // array size
// OrderedArray arr; // reference to array
OrderedArray src1 = new OrderedArray(4);
OrderedArray src2 = new OrderedArray(5);
// arr = new OrderedArray(maxSize); // create the array
src1.insert(1); //insert src1
src1.insert(17);
src1.insert(42);
src1.insert(55);
src2.insert(8); //insert src2
src2.insert(13);
src2.insert(21);
src2.insert(32);
src2.insert(69);
OrderedArray myArray = merge(src1, src2);
This is my expected output:
1
8
13
17
21
32
42
55
69
and this is my current output:
1
8
13
17
21
32
42
55
0
While merging two arrays you are comparing them, sorting and merging but what if the length of two arrays is different like Array1{1,3,8} and Array2{4,5,9,10,11}. Here we will compare both arrays and move the pointer ahead, but when the pointer comes at 8 in array1 and at 9 in array2, now we cannot compare ahead, so we will add the remaining sorted array;
Solution:-
(Add this code between loop to sort array and loop to print array)
while (i < numLength1) {
merged[k] = src1.array[i];
i++;
k++;
}
while (j < numLength2) {
merged[k] = src2.array[j];
j++;
k++;
}
To answer your main question, the length of your target array is src1.array.length + src2.array.length, so your loop condition should be one of:
while (k < src1.array.length + src2.array.length) {
while (k <= src1.array.length + src2.array.length - 1) {
Otherwise, you will never set a value for the last element, where k == src1.array.length + src2.array.length - 1.
But depending on how comprehensively you test the code, you may then find you have a bigger problem: ArrayIndexOutOfBoundsException. Before trying to use any array index, such as src1.array[i], you need to be sure it is valid. This condition:
if(src1.array[i] < src2.array[j]) {
does not verify that i is a valid index of src1.array or that j is a valid index of src2.array. When one array has been fully consumed, checking this condition will cause your program to fail. You can see this with input arrays like { 1, 2 } & { 1 }.
This revision of the code does the proper bounds checks:
if (i >= src1.array.length) {
// src1 is fully consumed
merged[k] = src2.array[j];
j++;
} else if (j >= src2.array.length || src1.array[i] < src2.array[j]) {
// src2 is fully consumed OR src1's next is less than src2's next
merged[k] = src1.array[i];
i++;
} else {
merged[k] = src2.array[j];
j++;
}
Note that we do not need to check j in the first condition because i >= src1.array.length implies that j is a safe value, due to your loop's condition and the math of how you are incrementing those variables:
k == i + j due to parity between k's incrementing and i & j's mutually exclusive incrementing
k < src1.array.length + src2.array.length due to the loop condition
Therefore i + j < src1.array.length + src2.array.length
If both i >= src1.array.length and j >= src2.array.length then i + j >= src1.array.length + src2.array.length, violating the facts above.
A couple other points and things to think about:
Be consistent with how you refer to data. If you have variables, use them. Either use numLength1 & numLength2 or use src1.length & src2.length. Either use myLength or use src1.array.length + src2.array.length.
Should a merge method really output its own results, or should the code that called the method (main) handle all the input & output?
Is the OrderedArray class safe to trust as "ordered", and is it doing its job properly, if you can directly access its internal data like src1.array and make modifications to the array?
The best way to merge two arrays without repetitive items in sorted order is that insert both of them into treeSet just like the following:
public static int[] merge(int[] src1, int[] src2) {
TreeSet<Integer> mergedArray= new TreeSet<>();
for (int i = 0; i < src1.length; i++) {
mergedArray.add(src1[i]);
}
for (int i = 0; i < src2.length; i++) {
mergedArray.add(src2[i]);
}
return mergedArray.stream().mapToInt(e->(int)e).toArray();
}
public static void main(String[] argh) {
int[] src1 = {1,17,42,55};
int[] src2 = {8,13,21,32,69};
Arrays.stream(merge(src1,src2)).forEach(s-> System.out.println(s));
}
output:
1
8
13
17
21
32
42
55
69

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.

Finding all possible subset sum which is equal to 0 out of set of positive and negative numbers? [duplicate]

This question already has answers here:
given a set of n integers, return all subsets of k elements that sum to 0
(3 answers)
Closed 6 years ago.
You have an array which has a set of positive and negative numbers, print all the subset sum which is equal to 0.
I can think of approach where i can cam make all powersets of givcen array and check if their sum is 0. BUt that does not llok like optimized solution to
me.
After reading looks a bit similar problem on net , looks like it can be solved with dynamic programming like below program to find if there is combination exist
to make sum 11 just an example ?
public boolean subsetSum(int input[], int total) {
boolean T[][] = new boolean[input.length + 1][total + 1];
for (int i = 0; i <= input.length; i++) {
T[i][0] = true;
}
for (int i = 1; i <= input.length; i++) {
for (int j = 1; j <= total; j++) {
if (j - input[i - 1] >= 0) {
T[i][j] = T[i - 1][j] || T[i - 1][j - input[i - 1]];
} else {
T[i][j] = T[i-1][j];
}
}
}
return T[input.length][total];
}
public static void main(String args[]) {
TestDynamic ss = new TestDynamic();
int arr1[] = {2, 3, 7, 8};
System.out.print(ss.subsetSum(arr1, 11));
}
But i am not sure how to extend above programe to
1) Include negative number
2) find combination of elements whick makes sum as zero( Above program just finds whether its possible to make given sum but does not
find which set of numbers makes it zero)
Here is a full implementation in Javascript. You can run it with node.js.
function target_sum(a, k, x)
{
if (k == a.length) return [];
if (a[k] == x) {
return [[a[k]]];
} else {
var s = target_sum(a, k + 1, x); // not using a[k]
var t = target_sum(a, k + 1, x - a[k]); // using a[k]
for (var i = 0; i < t.length; ++i) {
t[i].unshift(a[k]); // a[k] is part of the solution
s.push(t[i]); // merge t[] into s[]
}
return s;
}
}
var s = target_sum([1,4,5,2,7,8,-3,-5,-6,9,3,-7,-1,5,6], 0, 0);
for (var i = 0; i < s.length; ++i)
console.log(s[i].join(","));
Note that this is an exponential algorithm. Don't use it on large arrays.
Erwin Rooijakkers also pointed to the right direction. In particular, this post gives another algorithm. I could be wrong about the following – I believe that algorithm trades speed for space. It avoids staging arrays into the call stack, but it has to do more recursions to achieve that.
EDIT: about the algorithm you mentioned. It is not exponential, but it only works for positive numbers if I am right. Its time complexity is also proportional to the target sum, which may not be ideal depending on input.

Generate random numbers without duplicates using arrays only

I want to fill an array of size X with random integers from 0 to X with no duplicates. The catch is I must only use arrays to store the collections of int, no ArrayLists. How do I go about implementing this?
I don't understand why I can't seem to get this. But this is my most recent bit of code that fills the list but allows for duplicates.
System.out.print("Zero up to but excluding ");
int limit = scanner.nextInt();
// create index the size of the limit
int [] index = new int[limit];
for(int fill=0;fill<limit;fill+=1){
index[fill] = (limit);
}
int randomNumber = 0;
Random rand = new Random();
int [] randoms = new int[limit];
boolean flag = true;
// CODE TO NOT PRINT DOUBLES
for (int z=0;z<limit;z+=1){
randomNumber = rand.nextInt(limit);
int i=0;
while (i<limit){
if (index[i] == randomNumber){
flag = true;
}
else {
flag = false;
break;
}
i+=1;
}
if (flag == false){
randoms[z] = randomNumber;
index[z] = randomNumber;
}
}
System.out.println("Randoms: "+java.util.Arrays.toString(randoms));
Here's one way to do it:
Create an array of length N
Fill it from 0 to N-1
Run a for loop and swap randomly 2 indices
Code:
// Step 1
int N = 10;
int[] array = new int[N];
// Step 2
for(int i=0; i < N; i++)
array[i] = i;
// Step 3
for(int i=0; i < N; i++) {
int randIndex = (int) (Math.random() * N);
int tmp = array[i];
array[i] = array[randIndex];
array[randIndex] = tmp;
}
Why not rephrase the problem to shuffling an array of integers. First fill the array monotonically with the numbers 0 to X. Then use the Random() function to select one of the X numbers to exchange with the number in position 0. Repeat as many times as you may like. Done.
Here is your bug:
while (i<limit){
if (index[i] == randomNumber){
flag = true;
}
else {flag = false;break;} <--- rest of the array is skipped
i+=1;
}
after you generated a new number, you start to check for equality , however once you find that randomNumber!=index[i] (else statement) you break out of the while. look this: actual array is 3,4,5,1 your new number is 5, you compare it to 3 just to find out that they different so flag is set to false and break out happens.
Consider using another array filled with elements in order from 0 to X. Then, with this array, shuffle the elements around. How do you go about this? Use a loop to traverse through every single element of the array, and for each iteration, choose a random number from 0 to array.length - 1 and switch the elements at the index you're currently on and the random index. This is how it would look like,
In your main, you would have an array initialized by doing this,
int[] arr = new int[10];//10 can be interchangeable with any other number
for(int i = 0; i < arr.length; i++){
arr[i] = i;
}
shuffleArray(arr);
And the shuffle method would look like this,
public int[] shuffleArray(int[] arr){
Random rand = new Random();
for(int i = 0; i < arr.length; i++){
int r = rand.nextInt(arr.length);//generate a random number from 0 to X
int k = arr[i];
arr[i] = arr[r];
arr[r] = k;
}
}

Randomly filling a 2d boolean array with equal amounts of both values

I'm trying to find a way to fill a 2d array of length n with boolean values randomly. The array must have an equal amount of each value if n is even, and if n is odd the extra value must be the same boolean each and every time (doesn't matter which one). Any tips on how to do this in Java? I'm currently shuffling arrays that I make with equal amounts of both values, but this isn't truly random because there will always be n/2 (or n/2+1 and n/2-1 for the odd ns) of each value.
Any advice?
Given your requirements, filling the array with the amount you need, then shuffling it, is a good solution.
Make sure to use a truly random shuffling algorithm, such as the Fisher-Yates shuffle, not the "swap a random pair a bunch of times" method. If you're using Collections.shuffle or similar, you don't need to worry about this.
Adapting the Fisher-Yates shuffle to a 2D array is probably the simplest approach.
boolean[][] array = new boolean[rows][cols];
boolean alternating = false;
Random random = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
int k = random.nextInt(i * cols + j + 1);
int swapRow = k / cols;
int swapCol = k % cols;
boolean tmp = array[swapRow][swapCol];
array[swapRow][swapCol] = alternating;
array[i][j] = tmp;
alternating = !alternating;
}
}
This is pretty much a verbatim implementation of http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_.22inside-out.22_algorithm , except that we're filling the array as we go with falses and trues.
A different approach might be to randomise the position you are placing the next value rather than the value itself. You know ahead of time exactly how many of each value you are placing.
Something like:
List<Integer> indicesList = IntStream.range(0, n * n).collect(Collectors.toList());
Collections.shuffle(indicesList);
indicesList.stream().forEach(n -> array[n % size][n / size] = (n % 2 == 0));
By my understanding that should give you completely random placement of your values and an equal number of each.
Here's a real simple solution a coworker came up with. It looks to me like it would work and be truly random (please let me know if not, I have terrible intuition about that kind of thing), although it's definitely ugly. Would be pretty efficient compared to a shuffle I imagine.
public boolean[][] generateRandom2dBooleanArray(int length) {
int numFalses = (length*length)/2;
int numTrues = (length*length)/2;
if ((length*length)%2!=0) numTrues++;
boolean[][] array = new boolean[length][length];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if (Math.random() > 0.5) {//Or is it >= 0.5?
if (numTrues >= 0) {
array[i][j] = true;
numTrues--;
} else {
//Since boolean arrays are false by default, you could probably just break here to get the right anser, but...
array[i][j] = false;
numFalses--;
}
} else {
if (numFalses >= 0) {
array[i][j] = false;
numFalses--;
} else {
array[i][j] = true;
numTrues--;
}
}
}
}
}
return array;
}

Categories