对任意整数n,不妨设其最低(右)的数位对应2^k,于是n的二进制展开应该如下:
x x ... x 1 0 0 ... 0
其中最右边第一次1出现时,数位x可能是0或1,而最低的k+1位必然是“1 0 0 ... 0” ,即数位1之后是k个0。
于是相应的,n-1的二进制展开应该如下:
x x ... x 0 1 1 ... 0
也就是说,其最低位的k+1于n恰好相反,其余的(更高位各位相同)。
因此,二者做与运算(n & (n - 1))的结果应为:
x x ... x 0 0 0 ... 0
等效于将原n二进制展开的最低位1转置为0。
举个例子:
13 的二进制 1 1 0 1 , 最低位的1为0 0 0 1 。第一次将其反置为0,使之1 1 0 0 。
13-1=12,二进制 1 1 0 0, 13&12 即 1 1 0 1 & 1 1 0 0 ,成功得到 1 1 0 0 。
12-1=11,二进制 1 0 1 0 , 1 1 0 0 & 1 0 1 0 ,成功消除从右第二位的1,得到 1 0 0 0 。
8 -1= 7, 二进制 0 1 1 1, 1 0 0 0 & 0 1 1 1 ,成功全部将所有1置位。
int countOnes1 (unsigned int n)
{
int ones=0;
while (0 < n) //在n缩减至0之前,反复
{
ones++;
n &= n-1; //消除当前最靠右的1
}
return ones;
}