0

Possible Duplicate:
Randomly pick k bits out of n from a Java BitSet

Is there an easy way to generate a random BitSet of size n*n (e.g. 64) and exactly n (e.q 8) number of 1's in a random order?

What Ive thought about is that I could possibly generate a random bitset and check if bitSet.cardinality() is 8 and try again if its not, but that seems like a performance-bad solution.

Anyone have a better idea?

Community
  • 1
  • 1
rtc11
  • 747
  • 8
  • 23

4 Answers4

4

Using reservoir sampling, this can be done in O(N) time:

public static BitSet randomBitSet(int size, int cardinality, Random rnd) {
    if (0 > cardinality || cardinality > size) throw new IllegalArgumentException();
    BitSet result = new BitSet(size);
    int[] chosen = new int[cardinality];
    int i;
    for (i = 0; i < cardinality; ++ i) {
        chosen[i] = i;
        result.set(i);
    }
    for (; i < size; ++ i) {
        int j = rnd.nextInt(i+1);
        if (j < cardinality) {
            result.clear(chosen[j]);
            result.set(i);
            chosen[j] = i;
        }
    }
    return result;
}
finnw
  • 47,861
  • 24
  • 143
  • 221
  • Sorry I didn't spot the duplicate question before I answered. It already has [an answer](http://stackoverflow.com/a/10395706/12048) very similar to mine. – finnw Oct 22 '12 at 12:10
3

Get 8 different random numbers between 0 and 63. Set these bits at 1.

Your approach does not ensure exactly 8 1s, just a mean value of 8 1s for each 64 bits (if repeated enough times).

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • The *maximum* is 8. The mean is slightly less than 8. You can find the exact formula [here](http://en.wikipedia.org/wiki/Bloom_filter). – finnw Oct 11 '12 at 17:12
1

Create a list of the numbers you want to select e.g. from 0 to 63.

Shuffle the list.

Set the first n bits to 1, e.g. the first 8.

This will have an O(n^2) time complexity.


An alternative is to create a BitSet and keep setting random cleared bits until you have set 8 in total. You not need to test the cardinality.

int n = ...
Random rand = new Random();
BitSet bs = new BitSet(n * n);
for(int i = 0; i < n; i++) {
   int j = rand.nextInt(n * n);
   if (bs.get(j)) 
       i--;
   else
       bs.set(j);
}

This is typically, slightly worse than O(n)

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
1
  1. Set up an array of characters: {1 1 1 1 1 1 1 1 0 0 ... 0 0 0} with exactly the right number of 1's and 0's.

  2. Use the Fisher-Yates algorithm to do a random shuffle of your character array.

  3. Convert the shuffled array to a BitSet. Wherever a '1' character appears set the corresponding bit to 0b1. All other bits can be set to 0b0.

ETA: Thinking about it a bit more, you could probably create and shuffle the BitSet directly. THe underlying algorithm is still the same.

rossum
  • 15,344
  • 1
  • 24
  • 38