整数 二进制中1的个数前两天遇到这个问题,第一反应就是%2和>>1这两个操作。 int num = -1; int count1 = 0; for (int i = 0; i < 32;i ) { if (num % 2 != 0) { count1 ; } num = num >> 1; } 当然,这个思路差不多的方法还有 (((n >> i) & 1) == 1) 按位与1,通过&1拿到最右位,>>31次,也可以计算出1的个数。 unsigned int n1 = -1; 将负数通过自动类型的提升赋给一个无符号的整数n1,我们对于正数n1 &2和 >> 操作也一样可以拿到1的个数 ( 原理:整数在计算机内存是以补码形式存在 ) 当然,我看到了一个最经典的方法,n & (n-1)。 int n = -1; int count = 0; while (n) { n = n & (n - 1); count ; } printf("%d\n",count2); 刚开始看到这个n&n-1,真的是一脸懵逼,这都是哪跟哪,后面仔细的分析了下,的确也是这么一回事。给你们慢慢分析,逐字解析。 还是从正数负数分开分析 (32位太长,我们用8位代替) 正数:以红色框1为基准,(n-1)操作,补码从右往左开始,遇到1就停住,减去,也就是红色框1右边的0全部变成1,左边的原封不动,所以n&n-1也就是拿到了1左边的数,count ,n重新进入循环判断,如果不为0,就代表补码还存在1,重复操作。 (用原码去理解,正数原码补码都一样) 负数:我们要知道负数的补码是原码取反加一,对于一个(负数-1) & 负数,就很难去理解,所以我也是通过图片帮助理解。 首先我们要知道 n-1在计算机底层的操作是n (-1),我们通过一个数与32位1,也就是-1的补码形式,进行相加,溢出之后,就是n-1的效果,这里必须要再次感叹计算机的创造者。 n-1:依然以红色框1为基准,与-1的补码进行相加,很清楚的可以看到,右边开始,第一个1,也就是红色框1变为0,红色框1左边的数都原封不动,为什么会这么神奇呢? 之后每一位0或者1都是两次 1,依然保持不变,与(-1)进行位相加要加一次,还有一次是后面的溢出也需要加一次。0 1 1=0,1 1 1=1。 因此,n&(n-1也)是一样拿到了红色框1左边的原封不动的数,和正数也是同样的原理。 总结一下,这个方法对于正负数都是一样的,以补码右边开始第一个1位基准,(n-1)保持该1的左边原封不动,右边取反,再&按位与运算,count 。新的n进行判断,n !=0 则代表里面还有1,n==0则代表n里面没有1,结束循环。 |
|