使用n位数生成数字(类似于生成n位值的子集)

时间:2017-02-23 16:18:25

标签: c algorithm optimization bit-manipulation

给出一个数字' n'和相应的二进制值。我想生成n的所有组合,只使用' n'中设置的位。

例如:如果n = 11且其二进制表示为1011,则组合为:

00000
00001
01000
01001
10000
10001
11000
11001

示例2:如果n = 49且其二进制表示为11001,则组合为:

Runpath Search Paths = @executable_path/Frameworks

最简单的方法是编写一个C子程序来生成这些组合,但是,我需要一些有效的方法/算法来生成这些组合(一些类似于non-standard implementation的位操作技术)。

感谢。

3 个答案:

答案 0 :(得分:5)

这是一个使用简单比特琐事的技术的例证。它使用无符号值的二进制算术的保证语义。

在下面的i = n & (i - n)表达式中,所有子表达式in(i - n)n & (i - n)都是相同类型,{{1并且不受整数提升规则的影响。在数学上,子表达式unsigned int以2 m 为模,其中2 m - 1是可由{{1}表示的最大值}。

(i - n)

示例步骤

假设unsigned int为49或0000000000110001 2,且当前值#include <stdio.h> int main(void) { unsigned int n = 49; unsigned int i; for (i = 0; ; i = n & (i - n)) { printf("%u", i); if (i == n) break; putchar(' '); } putchar('\n'); return 0; } 为16或0000000000010000 2。然后对于16位,2的补码算法,我们有:

n

这与众所周知的技术相似,即将无符号值i中的最低“1”位设置为0000000000010000₂ 0000000000110001₂ - ---------------- 1111111111011111₂ 0000000000110001₂ & ---------------- 0000000000010001₂ (= 17) ,这是有效的,因为对带有两个补码的数字进行AND运算只会留下结果中设置了最低的'1'位。

答案 1 :(得分:0)

  1. 获取您的号码的二进制字符串。
  2. 创建标记为Z。
  3. 的树节点
  4. 设节点:= Z。
  5. 设N:= 1。
  6. 读取字符串的符号N(从左侧开始,1个索引)
  7. 如果符号为1,则添加两个节点子节点;标记节点标签为+ 1的第一个子节点,另一个节点标签为+ 0.如果符号为0,则添加节点的一个子节点;使用节点标签+ 0标记子节点。
  8. 增加N的值。
  9. 递归地对节点的所有子节点重复步骤5 - 7,直到在步骤7中将N的值增加到大于原始二进制字符串长度的值。该条件终止了递归。
  10. 树构建完成后,树的叶子会标有您允许的值。访问叶子的任何树遍历机制都允许您恢复允许的二进制字符串。

答案 2 :(得分:0)

只通过某些允许的位来迭代整数?这个功能怎么样:

int NextMasked (int val, int mask) {
    return ((val | ~mask) + 1) & mask;
}

功能一步一步:

  • 取前一个值val并将所有位设置为1,这些位未在mask
  • 中设置
  • 将结果值增加1
  • 现在;清除我们之前设置的所有位,仅允许mask
  • 中设置的相同位
  • tada.wav;我们有了新的价值,我们将return转到来电。

让我们用您的示例(mask = 11和最初val = 0)对此进行测试:

Here all values are in binary:

val = 0000, mask = 1011, ~mask = 0100 (bits inverted)

(old)                          (new)
val        |~mask   +1          &mask

0000       0100     0101        0001
0001       0101     0110        0010
0010       0110     0111        0011
0011       0111     1000        1000
1000       1100     1101        1001
1001       1101     1110        1010
1010       1110     1111        1011
1011       1111    10000       00000  <-- zeroed, you know it ended

因为这很有趣,让我们测试你的另一个例子(mask = 49):

Here all values are in binary:

val = 00000, mask = 11001, ~mask = 00110 (bits inverted)

(old)                          (new)
val        |~mask   +1          &mask

00000      00110    00111       00001
00001      00111    01000       01000
01000      01110    01111       01001
01001      01111    10000       10000
10000      10110    10111       10001
10001      10111    11000       11000
11000      11110    11111       11001
11001      11111   100000      000000  <-- again, wrapped around (zeroed)

已经很晚了,我实际上没有在电脑上测试过。但这应该有效,或者提出想法......