给定一个位掩码,其中设置位描述另一个数字可以是1或0,并且未设置的位在该数字中必须为零。什么是迭代所有可能值的好方法?
例如:
000 returns [000]
001 returns [000, 001]
010 returns [000, 010]
011 returns [000, 001, 010, 011]
100 returns [000, 100]
101 returns [000, 001, 100, 101]
110 returns [000, 010, 100, 110]
111 returns [000, 001, 010, 011, 100, 101, 110, 111]
最简单的方法就是这样做:
void f (int m) {
int i;
for (i = 0; i <= m; i++) {
if (i == i & m)
printf("%d\n", i);
}
}
但这会迭代太多数字。它应该是32而不是2 ** 32。
答案 0 :(得分:13)
这有一个有点蠢蠢的技巧(在Knuth的“计算机程序设计的艺术”第4A卷第7.1.3节中有详细描述;见第150页):
给定掩码mask
和当前组合bits
,您可以使用
bits = (bits - mask) & mask
...从0开始继续运行直到你回到0.(使用无符号整数类型来实现可移植性;对于非二进制补码机器上的有符号整数,这将无法正常工作。无符号整数是一个无论如何,更好地选择被视为一组位的值。)
C:
中的示例#include <stdio.h>
static void test(unsigned int mask)
{
unsigned int bits = 0;
printf("Testing %u:", mask);
do {
printf(" %u", bits);
bits = (bits - mask) & mask;
} while (bits != 0);
printf("\n");
}
int main(void)
{
unsigned int n;
for (n = 0; n < 8; n++)
test(n);
return 0;
}
给出:
Testing 0: 0
Testing 1: 0 1
Testing 2: 0 2
Testing 3: 0 1 2 3
Testing 4: 0 4
Testing 5: 0 1 4 5
Testing 6: 0 2 4 6
Testing 7: 0 1 2 3 4 5 6 7
(...我同意000
的答案应为[000]
!)
答案 1 :(得分:3)
首先,目前还不清楚为什么000不会返回[000]。这是一个错误吗?
否则,给定掩码值“m”和符合标准(n&amp; ~m)== 0的数字“n”,我建议写一个公式来计算下一个更高的数字。一个这样的公式一次使用运算符“和”,“或”,“不是”和“+”。
答案 2 :(得分:1)
@Matthew的诡计令人惊叹。这里有一个不那么棘手,但遗憾的是Python中的效率低递归版本:
def f(mask):
if mask == "0":
return ['0']
elif mask == '1':
return ['0', '1']
else:
bits1 = f(mask[1:])
bits2 = []
for b in bits1:
bits2.append('0' + b)
if mask[0] == '1':
bits2.append('1' + b)
return bits2
print f("101") ===> ['000', '100', '001', '101']
答案 3 :(得分:0)
你可以做到暴力。 ;-) Ruby示例:
require 'set'
set = Set.new
(0..n).each do |x|
set << (x & n)
end
(其中set
是一个set数据类型,即删除重复项。)
答案 4 :(得分:0)
试试这段代码:
def f (máscara):
se máscara == "0":
voltar ['0 ']
elif máscara == '1 ':
voltar ['0 ', '1']
else:
bits1 = f (máscara [1:])
bits2 = []
para b em bits1:
bits2.append ('0 '+ b)
se máscara [0] == '1 ':
bits2.append ('1 '+ b)
voltar bits2
print f ("101") ===> ['000 ', '100', '001 ', '101']
éinteressante。