Gale-Shapley Algorithm - java

I want to write a program that matches n men [0,1,2,...,n-1] to n women [0,1,2,...,n-1] according to their preferences. These preferences are represented by n x n-matrices, one for the men and one for the women.
[ 0 2 1 ]
E.g. men: [ 1 0 2 ]. The rows represent each man from 0 to 2, and per row we see a man's 'top 3'.
[ 1 2 0 ]
In this example: man 0 prefers woman 0 over woman 2; woman 1 is both man1's and man2's most prefered partner.
Now, I want to make sure that the matchings are as ideal as possible. This can be done by using the Gale-Shapley Algorithm.
I have two questions:
Suppose that m0 and m1 both have w0 as their first pick. Then, we'll have to look at w0's preferences: suppose that m0 is ranked higher, then (m0,w0) is a (temporary) matching. What should I do next? Do I first match m2 to his first pick, or - since m1 is still free - do I match m1 to his second pick?
I've already implemented an algorithm that looks like this:
Basically, the input consists of the preference matrices of both men and women. The result should be an array like res = [2,0,1], meaning man 2 is matched to woman 0, m0 with w1 and m1 with w2.
public int[] match(int[][] men, int[][] women) {
int n = men.length;
boolean[] menFree = new boolean[n];
Arrays.fill(menFree, true);
int[] res = new int[n];
Arrays.fill(res, -1);
int free = n;
int m = 0;
while (free > 0 && m<n) {
for (int i = 0; i < n; i++) {
if(menFree[i]){
int w = men[i][m];
if(res[w]==-1){
res[w]=i;
menFree[i]=false;
free--;
} else {
int c = res[w];
int colI = 0;
int colC = 0;
for(int j=0;j<n;j++){
if(women[w][j]==i){
colI = j;
} else if(women[w][j]==c){
colC = j;
}
}
if(colI<colC){
res[w]=i;
menFree[c]=true;
menFree[i]=false;
} else {
//do nothing or change column here, depending on answer to my first question.
}
}
}
}
m++;
}
return res;
}
As you can see I'm not sure what to do with the else-part when the position of a man's (=M's) competitor is higher then the position of M himself. Also, if it turns out that I should at that point look for M's second pick, how can I do this? There's still a possibility that I'll have to return to the first pick of the man after M.
Thanks for helping me out.

I read the wiki. And I implement myself.I think I understand it but my program is not beautiful.Just for communication.
package algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class GaleShapley {
public static void main(String[] args) {
int[][] men = {{1, 2, 0}, {0, 1, 2}, {2, 1, 0}};
int[][] women = {{1, 2, 0}, {0, 1, 2}, {2, 1, 0}};
int[] res = match(men, women);
for (int i : res)
System.out.println(i);
}
static int[] match(int[][] men, int[][] women) {
Map<Integer, Integer> temp = new HashMap<>();
int size = men.length;
boolean[] menFree = new boolean[size];
boolean[] womenFree = new boolean[size];
Arrays.fill(menFree, true);
Arrays.fill(womenFree, true);
ArrayList<Integer> stillFree = new ArrayList<>();
while (stillFree.size() + temp.size() < size) {
for (int i = 0, j = 0; i < size; i++, j = 0) {
if (menFree[i]) {
for (; j < size; j++) {
//if the woman is free,make them a pair
if (womenFree[men[i][j]]) {
// make woman and man i pair, the woman's index is men[i][j]
temp.put(men[i][j], i);
menFree[i] = false;
womenFree[men[i][j]] = false;
break;
} else {
// the woman is not free,check her pair is whether stable
int pairMan = temp.get(men[i][j]);
boolean stable = checkStable(pairMan, i, men[i][j], women);
// not stable break them and make new pair
if (!stable) {
temp.put(men[i][j], i);
menFree[i] = false;
menFree[pairMan] = true;
break;
}
}
}
// if man i is still free , it means that he can't find a woman
if (menFree[i])
stillFree.add(i);
}
}
}
int[] stablePair = new int[2 * temp.size()];
int i = 0;
for (Map.Entry<Integer, Integer> entry : temp.entrySet()) {
stablePair[i] = entry.getValue();
i++;
stablePair[i] = entry.getKey();
i++;
}
return stablePair;
}
static boolean checkStable(int pairMan, int currentMan, int woman, int[][] women) {
// index of pairMan and currentMan
int p = 0, c = 0;
for (int i = 0; i < women.length; i++) {
if (women[woman][i] == pairMan)
p = i;
else if (women[woman][i] == currentMan)
c = i;
}
// p<c : the woman love p more than c, they are stable
return p < c;
}
}

Related

How to build an array of indexes which represent values of different array from the highest to the lowest?

The title may be a bit confusing so here's an instance. I have two arrays:
int [] scores;
scores = new int[5]; //(5,7,10,3,6)
int [] places;
places = new int[5]; //(1,2,3,4,5)
I need to somehow sort the second array (I can't change the first one), so it represents the highness of elements in the first array. 10 is the highest so its place has to be 1st, 3 is the lowest so its place has to be 5th.
After the sorting second array should look like this:
places = {4,2,1,5,3};
Here's my code, and I need some help to make it work the way it should.
do {
for (int i = 0; i < 5; i++) {
for (int j = 1; j < 5; j++) {
if (scores[i] < scores[j]) {
temp = places[i];
places[i] = places[j];
places[j] = temp;
flag = true;
} else {
flag = false;
}
}
}
} while (flag);
Thanks in advance
#Korashen adviced a pretty good solution,
Another way:
assume all the values of scores are different and positive, you can make a copy of the array,sort it, and by subtaction to know the indexes,
in your example:
before sorting :
scores = (5,7,10,3,6)
after sorting :
scores_sorted = (3,5,6,7,10)
the value of places will be by the following rule:
if(scores_sorted[i]-scores[j] == 0)
places[i] = j
full example:
int[] scores = new int[]{5, 7, 10, 3, 6};
int[] scores_sorted = scores.clone();
int[] places = new int[]{0,1,2,3,4};
sort(scores_sorted);
for(int i=0;i<5;++i){
for(int j=0;j<5;++j){
if(scores_sorted[i]-scores[j] == 0){
places[i] = j;
}
}
}
You can use any sorting algorithm over the places but, instead comparing the places, compare the scores indexed by places.
Here is the modified quickSort:
static int partition(int[] iarray, int[] varray, int begin, int end) {
int pivot = end;
int counter = begin;
for (int i = begin; i < end; i++) {
if (varray[iarray[i]] < varray[iarray[pivot]]) {
int temp = iarray[counter];
iarray[counter] = iarray[i];
iarray[i] = temp;
counter++;
}
}
int temp = iarray[pivot];
iarray[pivot] = iarray[counter];
iarray[counter] = temp;
return counter;
}
public static void quickSort(int[] iarray, int[] varray, int begin, int end) {
if (end <= begin) return;
int pivot = partition(iarray, varray, begin, end);
quickSort(iarray, varray, begin, pivot - 1);
quickSort(iarray, varray, pivot + 1, end);
}
The only change is add the varray argument and the comparison iarray[i] < iarray[pivot] to varray[iarray[i]] < varray[iarray[pivot]].
NOTE: places must be numbers from 0 to n - 1.
If places are keys instead indexes, you need an intermediate Map to convert the varray[iarray[i]] to varray[real_index_of.get(iarray[i])].
A running example could be:
int[] scores = new int[]{5, 7, 10, 3, 6};
int[] places = new int[]{0, 1, 2, 3, 4};
quickSort(places, scores, 0, places.length - 1);
System.out.println(Arrays.stream(scores).mapToObj(Integer::toString).collect(joining(", ")));
System.out.println(Arrays.stream(places).mapToObj(Integer::toString).collect(joining(", ")));
With output:
5, 7, 10, 3, 6
3, 0, 4, 1, 2
(your output is wrong since 5 is the second lowest value)

Moving data in an array to the left

I'm really new to Java and there's something wrong with the code. No errors were detected, but the output is odd.
The goal is to move the data in an array to the left. For example:
x = {1,2,3}
the new array should be {2,3,1}.
Now the code below only gives me {0,0,0}. It'd be nice if you point out the mistake and tell me what to do. Thanks a lot beforehand!
public class Project1 {
public static int[] shiftone(int[]n,boolean left) {
n = new int[n.length];
int save,save2;
if(left = true){
save = n[0];
save2 = n[(n.length-1)];
for (int i = 1; i < n.length-1; i++) {
n[i-1]=n[i];
}
n[n.length-1] = save;
n[n.length-2] = save2;
}
else{
save = n[n.length-1];
for (int i=0;i<(n.length-1);i++)
n[(n.length)-i] = n[(n.length-1)-1];
n[0] = save;
}
return n;
}
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int[] x;
int k;
boolean left;
System.out.print("Masukkan jumlah data yang ingin diinput: ");
k = input.nextInt();
System.out.println();
x = new int[k];
for (int i = 0; i < k; i++) {
System.out.print("Input data ke-"+i+": ");
x[i] = input.nextInt();
}
System.out.print("Array: "+Arrays.toString(x));
System.out.println();
System.out.print("Move to left? (true/false): ");
left = input.nextBoolean();
System.out.println();
int[] y;
y = new int[k];
y = shiftone(x,left);
System.out.print("New array: "+Arrays.toString(y));
}
}
As a simple solution for your goal, you can use this
public static int[] shiftone(int[] n, boolean left) {
// you don't need to shift anything if length = 1
if (n.length < 2) {
return n;
}
if (left) {
// save first element
int save = n[0];
for (int i = 1; i < n.length; i++) {
// shift from 1 to n
n[i-1] = n[i];
}
// insert saved element to array
n[n.length - 1] = save;
} else {
// the same
int save = n[n.length - 1];
for (int i = 1; i < n.length; i++)
n[n.length - i] = n[(n.length - 1) - i];
n[0] = save;
}
return n;
}
There is the very fast method to copy the array elements from one place to another. I don't know if this will be helpful to you since it seems to me your question is homework assignment. Nevertheless, I'll put the code with appropriate comments...
public class Answer {
public static void main(String[] args) {
//test case
int[] input = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(input));
//save the first element in the temporary variable
int temp = input[0];
//the fastest way to copy the array elements
//1st parameter is the source array
//2nd parameter is the source position (read: from which element to copy)
//3rd parameter is the destination (in this case the same array)
//4th parameter is the destination position (read: where to store the 1st element)
//5th parameter is the length of elements to copy (read: how many)
System.arraycopy(input, 1, input, 0, input.length - 1);
//finally store the saved element to the end
input[input.length - 1] = temp;
System.out.println(Arrays.toString(input));
}
}
If we don't want to code the moving on our own, we can use the method Collections.rotate . It takes a List and rotates the elements by a given distance. To use it, we need to convert the int array to a List<Integer>. The rotated list is converted back to an int array.
protected static int[] move(int[] input, int distance) {
List<Integer> inputList = Arrays.stream(input).boxed().collect(Collectors.toCollection(ArrayList::new));
Collections.rotate(inputList, distance);
return inputList.stream().mapToInt(Integer::intValue).toArray();
}
Usage:
public static void main(String[] args) throws Exception {
int[] input = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
int moveLeftOnce = -1;
int[] moved = move(input, moveLeftOnce); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
}
Please note:
Since Collections.rotate will move the elements in the given list, the list has to be modifiable. This is the case for an ArrayList. Therefore the code uses Collectors.toCollection(ArrayList::new) since there are (JavaDoc)
no guarantees on the type, mutability ... of the List returned
by Collectors.toList.

JAVA specific loop over Array 2D

I have this array :
int[][] multi = new int[][]{
{ 3, 4, 2},
{ 2, 2, 5 },
{ 1, 2 }
};
I would like to print the produce of each cells. It's pretty hard to explain so lets see some example :
For my table i need to print :
6 //(3*2*1)
12 //(3*2*2)
6 //(3*2*1)
12 //(3*2*2)
15 //(3*5*1)
30 //(3*5*2)
8 //(4*2*1)
16 //(4*2*2)
8 //(4*2*1)
16 //(4*2*2)
20 //(4*5*1)
40 //(4*5*2)
...
Size of table can change, i need a generic things.
Here is my start but it's not doing what i need. This is looping line by line...
for (int i = 0; i<multi[0].length; i++) {
for (int k = 0; k < multi.length; k++) {
for (int l = 0; l < multi[k].length; l++ ) {
System.err.println(multi[k][l]);
}
}
}
I thing you have to do that recursively if your dimensions of array is not fixed..
I came up the code for dynamic dimension of 2D array
public class HelloWorld{
static int[][] multi = new int[][]{
{ 3, 4, 2},
{ 2, 2, 5 },
{ 1, 2 }
};
static public void pattern(int row,int multip) {
if(row >= multi.length) {
System.out.println(multip);
return ;
}
for(int i = 0; i<multi[row].length;i++) {
multip*=multi[row][i];
row+=1;
pattern(row,multip);
row-=1;
multip/=multi[row][i];
}
}
public static void main(String []args){
pattern(0,1);
}
}
If your dimensions are fixed then you can also do that using above logic but for that if you want to do iterative then you have to repeatedly create loops inside loop.
It's not hard to explain if you use mathematics terms and what you need is simply a Cartesian product of the sets (i.e. each row) in your bidimensional array.
It could be a bit longer to explain here the theory about Cartesian product (X is the operator) but in practice you have to calculate the result of:
((multi[0] X multi[1]) X ...) X multi[n]
And you ends with a bidimensional array with a number of rows which is the product of all the cardinality of each set and each row has a number of elements which is the number of the sets (because each tupla has an element from each set).
Another thing is that the tuple are ordered i.e. the element of a set will be in the same position in all the tuples e.g. each tupla in position 0 will have an element of multi[0].
Knowing these properties is possible to create the product with a construction algorithm which puts the elements of the first set in the first column of the resulting set repeating them the necessary amount of time and then go on with the next set/next column.
At the end when you have your Cartesian product you can do anything you want e.g. calculate the product of the elements of each row.
public class CartesianProductProduct {
public int[][] product(int[][] sets) {
int cardinality = 1;
for (int is = 0; is < sets.length; is++) cardinality *= sets[is].length;
int[][] cartesianProduct = new int[cardinality][sets.length];
int curCardinality = 1;
for (int is = 0; is < sets.length; is++) {
curCardinality *= sets[is].length;
int repetition = cardinality / curCardinality;
int ie = 0;
for (int ic = 0; ic < cardinality; ic++) {
cartesianProduct[ic][is] = sets[is][ie];
if (repetition == 1) {
ie++;
} else if ((ic + 1) % repetition == 0) {
ie++;
}
ie = ie == sets[is].length ? 0 : ie;
}
}
return cartesianProduct;
}
public static void main(String[] args) {
int[][] multi = new int[][]{
{3, 4, 2},
{2, 2, 5},
{1, 2}
};
int[][] cartesianProduct = new CartesianProductProduct().product(multi);
for (int i = 0; i < cartesianProduct.length; i++) {
int prod = 1;
String s = "";
String sep = "";
for (int k = 0; k < cartesianProduct[i].length; k++) {
prod *= cartesianProduct[i][k];
s = s + sep + cartesianProduct[i][k];
sep = "*";
}
System.out.printf("%s //(%s)\n", prod, s);
}
}
}

Get all subsets of a set

import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
The result should be [[],[1],[2],[1,2]]
But I can't get the result, the exception is as follows:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
Your while loop is incorrect.
Made slightly more succinct with a for-loop:
import java.util.ArrayList;
public class Subset { //Generate all subsets by generating all binary numbers
public static ArrayList<ArrayList<Integer>> getSubsets2(ArrayList<Integer> set) {
ArrayList<ArrayList<Integer>> allsubsets =
new ArrayList<ArrayList<Integer>>();
int max = 1 << set.size(); //there are 2 power n different subsets
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
for (int j = 0; j < set.size(); j++) {
if (((i >> j) & 1) == 1) {
subset.add(set.get(j));
}
}
allsubsets.add(subset);
}
return allsubsets;
}
public static void main(String[] args) {
ArrayList<Integer> set = new ArrayList<Integer>(); //Create an ArrayList
set.add(1);
set.add(2);
System.out.println(getSubsets2(set));
}
}
Bear in mind that the subset operation is exponential, so you'll get a very large number of elements. The implementation above will only work with about 32 input elements, as that yields 2^32 output subsets, which will very easily run you over the limit of an array...
Your problem appears to be in your loop. If you look at it:
for (int i = 0; i < max; i++) {
ArrayList<Integer> subset = new ArrayList<Integer>();
int index = 0;
while (i > 0) {
if ((i & 1) > 0) {
subset.add(set.get(index)); //Add elements to a new ArrayList
}
i >>= 1;
index++;
}
allsubsets.add(subset);
}
You'll notice that the outside for-loop is trying to count i upwards from zero, and the inner while loop counts it back to zero every iteration, so the outer loop runs forever.
Here is a Java 8 solution for this question:
public Set<Set<Integer>> getSubsets(Set<Integer> set) {
if (set.isEmpty()) {
return Collections.singleton(Collections.emptySet());
}
Set<Set<Integer>> subSets = set.stream().map(item -> {
Set<Integer> clone = new HashSet<>(set);
clone.remove(item);
return clone;
}).map(group -> getSubsets(group))
.reduce(new HashSet<>(), (x, y) -> {
x.addAll(y);
return x;
});
subSets.add(set);
return subSets;
}
Program runs forever. Below statement execute continuesly and getting outOfMemory. Variable i value is never bigger than max value, check it.
`subset.add(set.get(index));`
In a nutshell, your inner while-loop is changing the outer for-loop's loop variable (i). This is disrupting the outer loop iteration. At the end of the inner loop the value of i is going to be zero ... which means that the outer loop will never terminate.
Given what you are doing, the fix is to use a different variable (say j) for the inner loop, and initialize it from i.
This illustrates why it is a bad idea to change a for-loop variable inside the loop.
how about a recursive solution?
vector<vector<int> > getSubsets(vector<int> a){
//base case
//if there is just one item then its subsets are that item and empty item
//for example all subsets of {1} are {1}, {}
if(a.size() == 1){
vector<vector<int> > temp;
temp.push_back(a);
vector<int> b;
temp.push_back(b);
return temp;
}
else
{
//here is what i am doing
// getSubsets({1, 2, 3})
//without = getSubsets({1, 2})
//without = {1}, {2}, {}, {1, 2}
//with = {1, 3}, {2, 3}, {3}, {1, 2, 3}
//total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}
//return total
int last = a[a.size() - 1];
a.pop_back();
vector<vector<int> > without = getSubsets(a);
vector<vector<int> > with = without;
for(int i=0;i<without.size();i++){
with[i].push_back(last);
}
vector<vector<int> > total;
for(int j=0;j<without.size();j++){
total.push_back(without[j]);
}
for(int k=0;k<with.size();k++){
total.push_back(with[k]);
}
return total;
}
}

Arrays.sort not filling array, overwriting values that are already in the array

I need to generate an array int[] randomNumbers of random numbers with no duplicates. To do this, I make an array with all values that can go into randomNumbers, then use a random number generator to pick one out of the list, check if it's already in randomNumbers, and if it isn't, put it in randomNumbers.
(I want numbers between 1 and max, not 0 and max-1)
To be able to use Arrays.sort(int[]), the list needs to be sorted. So I use a third array, with the same values as randomNumbers called sortedNumbers, and sort it on every iteration:
public int[] uniqueRandom(int max, int numRequired) {
if (max < numRequired) {
numRequired = max;
}
int[] randomNumbers = new int[numRequired];
int[] sortedNumbers = new int[numRequired];
int[] sequentialNumbers = new int[max];
for (int i = 1; i < max; i++) {
sequentialNumbers[i] = i;
System.out.println(sequentialNumbers[i]);
}
int p = 0;
while (p < numRequired) {
int j = r.nextInt(max) + 1;
System.out.println("J:" + j);
if (Arrays.binarySearch(sortedNumbers, j) >= 0) {
System.out.println("Number Found:" + Arrays.binarySearch(randomNumbers, j));
} else {
randomNumbers[p] = j;
sortedNumbers[p] = j;
Arrays.sort(sortedNumbers);
for (int i = 0; i < randomNumbers.length; i++) {
System.out.println("rNum[" + i + "]:" + randomNumbers[i]);
}
System.out.println("\n");
for (int i = 0; i < randomNumbers.length; i++) {
System.out.println("sNum[" + i + "]:" + sortedNumbers[i]);
}
p++;
}
}
return randomNumbers;
}
My issue is that I'm getting an output where sortedNumbers is overwriting values. For uniqueRandom(5, 5) the output is:
J:2
rNum[0]:2
rNum[1]:0
rNum[2]:0
rNum[3]:0
rNum[4]:0
sNum[0]:0
sNum[1]:0
sNum[2]:0
sNum[3]:0
sNum[4]:2
J:2 // 2 already in the list, try again
J:2
J:4
rNum[0]:2
rNum[1]:4
rNum[2]:0
rNum[3]:0
rNum[4]:0
sNum[0]:0
sNum[1]:0
sNum[2]:0
sNum[3]:2
sNum[4]:4
J:5
rNum[0]:2
rNum[1]:4
rNum[2]:5
rNum[3]:0
rNum[4]:0
sNum[0]:0
sNum[1]:0
sNum[2]:2
sNum[3]:4
sNum[4]:5
J:2
J:3
rNum[0]:2
rNum[1]:4
rNum[2]:5
rNum[3]:3
rNum[4]:0
sNum[0]:0 // Should be:
sNum[1]:0 // 2
sNum[2]:2 // 3
sNum[3]:3 // 4
sNum[4]:5 // 5
J:4
rNum[0]:2
rNum[1]:4
rNum[2]:5
rNum[3]:3
rNum[4]:4
sNum[0]:0
sNum[1]:0
sNum[2]:2
sNum[3]:3
sNum[4]:4
So you can see the issue. I'm using java 1.7, and have no idea why it's doing this!
To solve your problem I would use a Set, that assure us to have unique results.
Below snipest will generate array with required number of unique integers.
Set<Integer> uniqueNumbers = new HashSet<Integer>();
Random r = new Random();
while(uniqueNumbers.size() < numRequired) {
uniqueNumbers.add(r.nextInt(maxRandom) + 1);
}
return uniqueNumbers.toArray(new Integer[0]);
You are putting the new number into both arrays using the same index. Your rNum array is filling from top down, but the sorted array is not: Each time you sort it, the new value moves down in the array and the zeros are always at the top. I think you could fix it by always putting the new number in the first position of the sorted array:
sortedNumbers[0] = j;
When you input J=5
the sortedNUm[] is
sNum[0]:0
sNum[1]:0
sNum[2]:2
sNum[3]:4
sNum[4]:5
next when you input J=3 (your p=3)
after
sortedNumbers[p] = j;
your sNUM[3] which is 4 is replaced by 3
hence after sorting it becomes
sNum[0]:0 // Should be:
sNum[1]:0 // 2
sNum[2]:2 // 3
sNum[3]:3 // 4
sNum[4]:5 // 5
notice 4 is not present
I suggest you initialize the array to -1 or 0 and add the variables at the start of array
like
sortedNumbers[0]=j;
and after Arrays.sort(); the first position will always be empty to add more numbers
While it doesn't answer the question, here is an alternative which is O(n) and work well provided max is not large.
public static void main(String[] args) {
System.out.println(Arrays.toString(uniqueRandom(20, 10)));
}
public static int[] uniqueRandom(int max, int numRequired) {
int[] possible = new int[max];
int[] ret = new int[numRequired];
for (int i = 0; i < max; i++)
possible[i] = i + 1;
Random r = new Random();
int numLeft = max;
for (int i = 0; i < numRequired; i++) {
int idx = r.nextInt(numLeft);
ret[i] = possible[idx];
if (idx < --numLeft)
possible[idx] = possible[numLeft];
}
return ret;
}
prints
[4, 10, 12, 19, 8, 3, 15, 1, 14, 7]
What I am trying to say is that perhaps you could make it simpler.
There are a few issues with your code:
since you only increment p when the new number j doesn't already exist in the arrays, that, combined with the fact that you sort the sortedArray first leads to the value actually being placed sometimes over an existing value (which shifted position due to the sort)
I don't understand what's the use of the sequentialNumbers array...
Here's an example which should work:
private static Random r = new Random();
public static void main(String[] args) {
System.out.println(Arrays.toString(uniqueRandom(10, 10)));
}
public static int[] uniqueRandom(int max, int numRequired) {
if (max < numRequired) {
numRequired = max;
}
int[] randomNumbers = new int[numRequired];
int[] sortedNumbers = new int[numRequired];
Arrays.sort(sortedNumbers);
int p = 0;
while (p < numRequired) {
int j = r.nextInt(max) + 1;
if(Arrays.binarySearch(sortedNumbers, j)<0) {
randomNumbers[p] = j;
System.arraycopy(randomNumbers, 0, sortedNumbers, 0, randomNumbers.length);
Arrays.sort(sortedNumbers);
p++;
}
}
return randomNumbers;
}

Categories