在C中有效地生成m& m == n(m是给定整数)的所有整数n

时间:2013-05-12 13:07:58

标签: algorithm bit-manipulation bitwise-operators

&安培;在C中是位AND。

示例:

m= 21(10101)

结果:

0 16 4 1 20 5 17 21

我的代码:

for(int i=0;i<=m;i++) 
    if ((i&m)==i) printf("%d ",i);

当m很大时,这将非常慢。

如何快速找到结果(答案很少,例如m = 2 ^ 30)?

3 个答案:

答案 0 :(得分:4)

i = 0
repeat
  print(i)
  i = (i + (NOT m) + 1) AND m
until i == 0

UPD:
更简单的代码:

i = 0
repeat
  print(i)
  i = (i - 1) AND m
until i == 0

答案 1 :(得分:4)

接受的答案是正确的,但细节上有点稀疏,所以这里的为什么会起作用

观察集合{ n | n & m == n }是所有n的集合,以使n中的位成为m中的位的子集。如果所有这些位都在从最低有效位开始的组中,则可以通过简单地从0计数到m来生成它们。

但是它们不一定分组,因此位之间可能有空格。应该跳过这些空格,如何通过递增跳过这些位?

那么你可以通过使它们成为1来进行传播(不完全跳过)传播。但是这些位留下了一些垃圾,必须将其清除掉。

因此,首先设置间隙中的位:i | ~m(等效写为i ^ ~mi + ~m,因为~m中的位保证不与任何位重叠在i)。

然后执行增量(+1),然后扔掉空隙中留下的任何垃圾:& m

总计:((i | ~m) + 1) & m


对于新代码,观察通过间隙进行借位传播更容易,因为为了传播间隙,应该用零填充它已经存在的零。因此,唯一的问题是,间隙中可能会留下一些垃圾,应该使用& m清除,总共(i - 1) & m

答案 2 :(得分:1)

一行代码:

for(i=m;i;i=(i-1)&m) printf("%d ",i);printf("0");