我想获得范围为1 ... 2 ^ k-1的二进制表示的整数列表。或者,我需要一个k位的所有可能组合的列表。所以,例如,假设k是3我需要:
001
010
011
100
101
110
111
由于我计划在Java中执行此操作,我正在考虑使用BitSet来表示每个数字,并将值存储在列表中,但我认为这个问题可能与语言无关。基本上,我需要弄清楚生成整个集合的算法。
我认为我需要一个递归解决方案,这会考虑先前设置的位。
void fill(int k, int i, boolean wasSet) {
if (i==k) return;
BitSet bs = new BitSet();
for (int j=0; j<k; j++) {
if (!wasSet) {
bs.set(i);
fill(k, i, true);
} else {
fill(k, j, false);
}
}
注意:这个函数原型显然是非常错误的。
注意2:我真的很想避免使用字符串,因为我后来需要使用这些值来执行其他一些计算,而BitSet对此非常方便
答案 0 :(得分:6)
您可以拥有以下内容:
for(int i=0 ; i<n ; i++){
System.out.println(Integer.toBinaryString(i));
}
其中n
是您想要的最大数字。
要使用BitSet
,java 7会有BitSet.valueOf(byte[])和BitSet.toByteArray()
。
有关详细信息,请查看this post。
答案 1 :(得分:4)
奇怪的问题,一些先进的概念,但也有一些逻辑上的差距。
但是,如果你想要每个值的位集,那么做同样的事情(就像tokhi建议的那样):
int size = 1 << bits;
ArrayList<BitSet> results = new ArrayList<>(size);
for (int val = 1; val < size; val++) {
BitSet bs = new BitSet(bits);
results.add(bs);
for (int b = 0; b < bits; b++) {
if ( ((val >>> b) & 1) == 1) {
bs.set(b);
}
}
}
在关于递归或循环是否更好的'聊天'之后,我已经把这个测试放在一起......
我已经修改了上面的代码以提高效率,但是,我对Dukeling的代码进行了相对较大的更改,以便它返回所有 BitSets而不是仅修改一个而不存储结果。
请注意,递归代码中存在“错误”,因为它返回的no-bits-set值不应该是结果的一部分......
无论如何,这只是值得深思的事。
这是我的测试代码:
import java.util.ArrayList;
import java.util.BitSet;
public class Junk {
private static final ArrayList<BitSet> loop(final int bits) {
int size = 1 << bits;
ArrayList<BitSet> results = new ArrayList<>(size);
for (int val = 1; val < size; val++) {
BitSet bs = new BitSet(bits);
results.add(bs);
int v = val;
int b = 0;
while (v != 0) {
if ( (v & 1) == 1) {
bs.set(b);
}
b++;
v >>>= 1;
}
}
return results;
}
private static final ArrayList<BitSet> recurse(final int bits) {
ArrayList<BitSet> retval = new ArrayList<BitSet>();
BitSet bitset = new BitSet(bits);
fill(bitset, 0, bits, retval);
return retval;
}
private static final void fill(final BitSet bs, final int k, final int n, final ArrayList<BitSet> results)
{
if (k == n) {
results.add((BitSet)bs.clone());
return;
}
bs.set(k, false);
fill(bs, k+1, n, results);
bs.set(k, true);
fill(bs, k+1, n, results);
}
private static final void exercise(final int bits) {
double acnt = 0;
double bcnt = 0;
long atime = 0L;
long btime = 0L;
for (int i = 0; i < 1000; i++) {
final long as = System.nanoTime();
acnt += recurse(bits).size();
atime += System.nanoTime() - as;
final long bs = System.nanoTime();
bcnt += loop(bits).size();
btime += System.nanoTime() - bs;
}
acnt /= 1000;
bcnt /= 1000;
System.out.printf(" Bits %d: ms/call -> recurse %.3fms loop %3fms (recurse %.1f/%d loop %f.1/%d\n",
bits, atime / 1000000.0, btime / 1000000.0, acnt, 1<<bits, bcnt, (1 << bits) - 1);
}
public static void main(String[] args) {
System.out.println("warmup");
exercise(3);
exercise(2);
exercise(1);
System.out.println("real runs");
exercise(1);
exercise(2);
exercise(3);
exercise(4);
exercise(5);
exercise(6);
exercise(7);
exercise(8);
exercise(9);
exercise(10);
exercise(11);
}
}
这是我机器上的输出:
warmup
Bits 3: ms/call -> recurse 12.324ms loop 7.109403ms (recurse 8.0/8 loop 7.000000.1/7
Bits 2: ms/call -> recurse 2.949ms loop 2.392226ms (recurse 4.0/4 loop 3.000000.1/3
Bits 1: ms/call -> recurse 1.681ms loop 1.038053ms (recurse 2.0/2 loop 1.000000.1/1
real runs
Bits 1: ms/call -> recurse 1.743ms loop 0.865739ms (recurse 2.0/2 loop 1.000000.1/1
Bits 2: ms/call -> recurse 1.996ms loop 0.261967ms (recurse 4.0/4 loop 3.000000.1/3
Bits 3: ms/call -> recurse 3.150ms loop 0.544942ms (recurse 8.0/8 loop 7.000000.1/7
Bits 4: ms/call -> recurse 4.876ms loop 0.932031ms (recurse 16.0/16 loop 15.000000.1/15
Bits 5: ms/call -> recurse 6.128ms loop 1.775841ms (recurse 32.0/32 loop 31.000000.1/31
Bits 6: ms/call -> recurse 9.937ms loop 3.209335ms (recurse 64.0/64 loop 63.000000.1/63
Bits 7: ms/call -> recurse 21.005ms loop 7.221974ms (recurse 128.0/128 loop 127.000000.1/127
Bits 8: ms/call -> recurse 38.715ms loop 16.410275ms (recurse 256.0/256 loop 255.000000.1/255
Bits 9: ms/call -> recurse 69.904ms loop 41.330404ms (recurse 512.0/512 loop 511.000000.1/511
Bits 10: ms/call -> recurse 132.053ms loop 88.952120ms (recurse 1024.0/1024 loop 1023.000000.1/1023
Bits 11: ms/call -> recurse 255.921ms loop 193.370808ms (recurse 2048.0/2048 loop 2047.000000.1/2047
答案 2 :(得分:3)
以下是我提出的递归解决方案。
简单地说,对于每个位置,都试图设置该位,然后进行递归。
它对所有排列使用相同的BitSet
。如果您希望每个都有一个,您可能需要复制它。
static BitSet bs = new BitSet(3);
static void fill(int k, int n)
{
if (k == n)
{
System.out.println(bs);
return;
}
bs.set(k, false);
fill(k+1, n);
bs.set(k, true);
fill(k+1, n);
}
public static void main(String[] args)
{
fill(0, 3);
}
答案 3 :(得分:1)
嗯,你总是可以手动增加:
int k = 3; //or something else
ArrayList<Boolean[]> combinations = new ArrayList<>();
boolean[] current;
void increment() {
for(int i = 0; i<k; i++) {
if(current[i]) {
current[i] = false;
} else {
current[i] = true;
break;
}
}
}
void fill() {
current = new boolean[k];
combinations.add(current);
final int max = (int) Math.pow(2, k);
for(int i = 1; i< max; i++) {
current = current.clone(); //not sure about this -> google java array copy/clone
increment();
combinations.add(current);
}
}
这会将LSB(最低有效位)置于地址0,但由于它包含所有组合,这应该无关紧要,只有当你将其表示为MSB(大多数 - || - )时才会对它进行排序在索引0。
答案 4 :(得分:0)
这是解决问题的简单方法,它相当于遍历完整的二叉树并记录每条路径。
public class Combinations {
public static void combinations(int i,int k,char[]buff) {
if(i<k) {
buff[i] = '0';
combinations(i+1,k,buff);
buff[i] = '1';
combinations(i+1,k,buff);
}
else System.out.println(String.valueOf(buff));
}
public static void main(String[] args) {
int k = 3;
combinations(0,k,new char[k]);
}
}
答案 5 :(得分:0)
import java.util.LinkedList;
import java.util.Queue;
public class GenerateBNo
{
static void generatePrintBinary(int n)
{
Queue<String> q = new LinkedList<String>();
q.add("1");
while(n-- > 0)
{
String s1 = q.peek();
q.remove();
System.out.println(s1);
String s2 = s1;
q.add(s1 + "0");
q.add(s2 + "1");
}
}
public static void main(String[] args)
{
int n=10;
generatePrintBinary(n);
}
}