求一个数的二进制序列中1的个数(3种方法)

2019-04-14 18:38发布

前言:一个数要存储在计算机中,是以该数二进制补码形式存储的。 法1(不推荐使用): 思路:当我们想要得到一个十进制数的每一位时,通常是采用模10除10的方法,模10得到最低位,除10得到高位,一直重复。那么想要得到一个数的二进制的每一位时,也可以采用模2除2的方法。 //求一个数存储在二进制数中1的个数(补码形式存储,所以算的是该数二进制补码中1的个数) int count_one1(int m) //不适用于负数 { int count = 0; while (m) { if (m % 2 == 1) //最低位是1 { count++; } m /= 2; //处理完最低位后将其丢掉 } return count; } int main() { int n = 1; int count = count_one1(n); printf("%d ", count); system("pause"); return 0; } 但我们发现,一个负数不论%2还是/2结果永远是负数,所以用上述代码求解1的个数时永远都是0个,所以此种方法只适用于正数。 法二(推荐使用): 思路:我们知道一个数的二进制&1可得该数二进制最低位是0还是1,那么在此基础上,只要我们每次判断完最低位后右移一位就可以得到此时最低位的值,移31位便可得到该数二进制中1的个数。 int count_one2(int m) //必须要循环32次,效率太低 { int i = 0; int count = 0; for (i = 0; i < 32; i++) { if (((m >> i) & 1) == 1) { count++; } } return count; } int main() { int n = -1; int count = count_one2(n); printf("%d ", count); system("pause"); return 0; } 但是此种方法效率太低,如果一个数的二进制补码中1全部集中在低位,而高位无0,循环32次无疑拉低了程序的运行效率。 法3(推荐使用): 思路:我们发现一个数和该数减1后做按位与操作再赋给该数,即某数=某数&(某数-1),每执行一次,该数二进制最右边的1就会丢掉。那么我们便可以知道,只要一个数在变成0之前能执行多少次某数=某数&(某数-1)操作,该数的二进制便有多少个1。 #define _CRT_SECURE_NO_WARNINGS 1 #include #include int count_one3(int m) { int count = 0; while (m) { m = m&(m - 1); count++; } return count; } int main() { int n = -1; int count = count_one3(n); printf("%d ", count); system("pause"); return 0; } 此方法既适用于负数,又大大提高了程序执行的效率。