第一次听说汉明距离来源于一次面试,当时问了个题目:
已知一个无符号的二进制整数n,int长度,求二进制中1的个数
int Method01(int n)
{
int count(0); //声明计数变量
while (n != 0)
{
count += n & 1;
n >>= 1; //右移
}
return count;
}
e.g.:
n | 0101 1000 |
n - 1 | 0101 0111 |
n & (n - 1) | 0101 0000 |
int Method02(int n)
{
int count(0);
while (n != 0)
{
n &= n - 1;
++count;
}
return count;
}
采用分冶的思想,为了统计4个字节的中有1的个数,将数据的相邻两位分成一组,统计出每组中含有1的个数:
比相邻的两位x=10构成一组,要统计这组含有1的个数,低位中1的个数:x & 01,高位中1的个数(x >> 1) & 01。这里n为4byte,则表示为n & 0x55555555 + (x >> 1) & 0x55555555。
将上一步计算的结果保存到n中,再将每相邻两组即4位构成新一组,再进行计算,如此只须做4次运算,即可得出最终结果。
e.g.: 以8bit为例
n = 0110 1100
0x55 = 0101 0101
---------------------------------------------------------------------------------------------------------------------
n = |0 1|1 0|1 1|0 0| 将n按每两位分成一组
----------------------------------------------------------------------------------------------------------------------
|0 1|0 0|0 1|0 0| n与0x55=0101 0101相与的结果:低位中为1的个数
+ |0 0|0 1|0 1|0 0| n>>1与0x55=0101 0101相与的结果:高位中为1的个数
= |0 1|0 1|1 0|0 0| 将两个结果相加
= |0 1 0 1|1 0 0 0| 4个一组
----------------------------------------------------------------------------------------------------------------------
|0 0 0 1|0 0 0 0| n与0x33=0011 0011相与的结果
+|0 0 0 1|0 0 1 0| n>>2与0x33=0011 0011相与的结果
=|0 0 1 0|0 0 1 0| 相加
=|0 0 1 0 0 0 1 0| 8个一组
----------------------------------------------------------------------------------------------------------------------
|0 0 0 0 0 0 1 0| n与0x0F=0x0000 1111相与的结果
+|0 0 0 0 0 0 1 0| n>>4与0x0F=0x0000 1111相与的结果
=|0 0 0 0 0 1 0 0| 相加
= 4 最终结果,即为4
对于4byte的int型,代码如下:
int Method03_HammingWeight(int n)
{
n = (n & 0x55555555) + ((n >> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F);
n = (n & 0x00FF00FF) + ((n >> 8) & 0x00FF00FF);
n = (n & 0x0000FFFF) + ((n >> 16) & 0x0000FFFF);
return n;
}
上述代码就为Hamming Weight