求整数的二进制表示中1的个数,最直接的方式是求出其二进制表示,再计算出二进制表示中1的个数。但是这种方法的效率较低。因为我们只需要统计二进制表示中1的个数,所以没有必要将整数先转化为二进制,可以在对整数处理的过程中计数。整数转化为二进制,除了直接除以2以外,位操作的右移一位可以实现同样的功能。右移过程中会将最后一们直接丢弃,因此在右移操作之前需要先判断最后一们是否为1,使用“与”操作可以实现。例如如果n的最后一样是1,那么a & 0x01 = 1,否则a & 0x01 = 0。由此可以写出实现代码:
1 #include <stdio.h> 2 3 int main() 4 { 5 int n, s = 0; 6 scanf("%d", &n); 7 while(n) 8 { 9 s += n & 0x01; //判断最后一位是否为1 10 n >> 1; // 移位操作 11 } 12 printf("%d\n", s); 13 return 0; 14 }
对于上述程序还存在可以改进的地方:操作过程中只考虑二进制表示中的“1”。具体实现如下:
1 #include <stdio.h> 2 3 int main() 4 { 5 int n, s = 0; 6 scanf("%d", &n); 7 while(n) 8 { 9 n &= (n - 1); 10 s++; 11 } 12 printf("%d\n", s); 13 return 0; 14 }
然后回复中的这些代码不懂
1 你可以试试这几种算法,会比你的快n倍。 2 3 #if 0 4 x = (x & 0x55555555) + ((x >> 1) & 0x55555555); 5 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 6 x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f); 7 x = (x & 0x00ff00ff) + ((x >> 8) & 0x00ff00ff); 8 x = (x & 0x0000ffff) + ((x >> 16) & 0x0000ffff); 9 #elif 0 10 // mit hackmem count 11 x = x - ((x >> 1) & 0x55555555); 12 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 13 x = (x + (x >> 4)) & 0x0f0f0f0f; 14 x = x + (x >> 8); 15 x = x + (x >> 16); 16 x &= 0x7f; 17 #elif 0 18 x = x - ((x >> 1) & 0x55555555); 19 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 20 x = (x + (x >> 4) & 0x0f0f0f0f); 21 x = (x * 0x01010101) >> 24; 22 #elif 0 23 x = x - ((x >> 1) & 0x55555555); 24 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 25 x = (x + (x >> 4) & 0x0f0f0f0f) % 255; 26 #elif 0 // faster 27 x = x - ((x >> 1) & 0x77777777) - ((x >> 2) & 0x33333333) - ((x >> 3) & 0x11111111); 28 x = (x + (x >> 4) & 0x0f0f0f0f); 29 x = (x * 0x01010101) >> 24; 30 #else 31 x = __builtin_popcount(x); // for gcc 32 #endif
转自: