通过掩码的所有可能值迭代数字的好方法是什么?

时间:2011-09-01 22:58:13

标签: algorithm bit-manipulation

给定一个位掩码,其中设置位描述另一个数字可以是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。

5 个答案:

答案 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。