hamming weight_popcount或者hamming weight(二进制1的个数问题)
第一次寫關(guān)于算法的問題。今天數(shù)據(jù)庫課老師在講數(shù)據(jù)庫底層實現(xiàn)的時候提到了位圖索引,最后歸結(jié)為1的個數(shù),以前看到很多次關(guān)于1的個數(shù)的計算,今天總結(jié)一下。
最開始是有《編程之美》里面的問題引出的:如何最快地讀取到二進制中1的個數(shù).
最開始我也是感覺一個個地數(shù)不就完了,但是人家說了要求最快。一個個的數(shù)是O(N)級的。
1. 比如:int count=0;
for(;x;x>>1)
{
count++;
}//當然也有每次用x直接除以2 的。
2.后來就是用x&(x-1)的結(jié)果是否為0來判斷,如果為零,有一個1,否則沒有。
所以有:
for(;x;count++)
x&=x-1;
3.查表大法,就是一一列舉這n位二進制所有的可能到數(shù)組中,然后直接查表就是了,這里就不贅述了
4.這個新的方法叫shift and add,正如名字一樣,該算法用的就是shift 和add(移位和加法):
對于n位二進制數(shù),最多有n個1,而n必定能由n位二進制數(shù)來表示,因此我們在求出某k位中1的個數(shù)后,可以將結(jié)果直接存儲在這k位中,不需要額外的空間。
以4位二進制數(shù)abcd為例,最終結(jié)果是a+b+c+d,循環(huán)的話需要4步加法
那么我們讓abcd相鄰的兩個數(shù)相加,也就是 a+b+c+d=[a+b]+[c+d]
[0 b 0 d]
[0 a 0 c]
--------
[e f] [ g h]
ef=a+b ? gh=c+d 而 0b0d=(abcd)&0101,0a0c=(abcd)>>1 &0101
[ef] ?[gh]再相鄰的兩組相加
[00 ef]
[gh]
--------
i j k l
ijkl=ef+gh ?gh=(efgh)&& 0011 ,ef=(efgh)>>2 & 0011
依次入次遞推。需要log(N)次
代碼如下:
typedef unsigned __int64 uint64; //assume this gives 64-bits
const uint64 m1 = 0x5555555555555555; //binary: 0101...
const uint64 m2 = 0x3333333333333333; //binary: 00110011..
const uint64 m4 = 0x0f0f0f0f0f0f0f0f; //binary: 4 zeros, 4 ones ...
const uint64 m8 = 0x00ff00ff00ff00ff; //binary: 8 zeros, 8 ones ...
const uint64 m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const uint64 m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
int popcount_1(uint64 x) {
x = (x & m1 ) + ((x >> 1) & m1 );
x = (x & m2 ) + ((x >> 2) & m2 );
x = (x & m4 ) + ((x >> 4) & m4 );
x = (x & m8 ) + ((x >> 8) & m8 );
x = (x & m16) + ((x >> 16) & m16);
x = (x & m32) + ((x >> 32) & m32);
return x;
}
5.對shift and add的優(yōu)化:
看到有三種優(yōu)化,這里只提兩種吧
1
int popcount_2(uint64 x)
{
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
x += x >> 8;
x += x >> 16;
x += x >> 32;
return x & 0x7f;
}
2.
int popcount_3(uint64 x) {
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
return (x * h01)>>56;
據(jù)說這可是MIT的牛人想出來的高招(當時是求余,現(xiàn)在換成除法了更快)
我也是參見了wikipedia(但是看不懂)和http://blog.ibread.net/375/pop-count-problem/上面的文章。
int popcount_3(uint64 x) {
x -= (x >> 1) & m1;
x = (x & m2) + ((x >> 2) & m2);
x = (x + (x >> 4)) & m4;
return (x * h01)>>56;
總結(jié)
以上是生活随笔為你收集整理的hamming weight_popcount或者hamming weight(二进制1的个数问题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: als算法参数_Spark2.0协同过滤
- 下一篇: .net core发布 正在发现数据上下