之前碰到一些类似于数一个数二进制里有多少1和找最高位等等这样的问题,虽然手写起来也不麻烦,但是看到别人的代码里面很优美的直接塞了一个函数就解决了,还是想学习一下的。
1、最低位1的位数
int __builtin_ffs (unsigned int x)
x=
1
1
2
11_2
112时返回1,x=
11
0
2
110_2
1102时返回2,以此类推。
当然塞一个正的int进去也是没有问题的,一般不会用到负数二进制表示。
如果要返回最低那一位的值的话用lowbit(x)=(x)&(-x)更优美一点。
2、1的个数
int __builtin_popcount (unsigned int x)
这个是比较常用的,时间复杂度貌似为
O
(
log
x
)
O(\log x)
O(logx)级别
除此之外,统计1的个数的常用方法是打表,例如,把 [ ( 00000000 ) 2 , ( 11111111 ) 2 ] , 即 [ 0 , 2 8 − 1 ] [(00000000)_2,(11111111)_2],即[0,2^8-1] [(00000000)2,(11111111)2],即[0,28−1]内的数有多少个1计算出来,存在一个数组count里面,对于任意一个32位无符号整数(unsigned int),将其切分为4段,从高到低表示为 x 1 , x 2 , x 3 , x 4 x_1,x_2,x_3,x_4 x1,x2,x3,x4那么1的个数就是 c o u n t [ x 1 > > 24 ] + c o u n t [ x 2 > > 16 ] + c o u n t [ x 3 > > 8 ] + c o u n t [ x 4 ] count[x_1>>24]+count[x_2>>16]+count[x_3>>8]+count[x_4] count[x1>>24]+count[x2>>16]+count[x3>>8]+count[x4],可以优化不少常数,如果存储空间足够,通常会保存 2 16 − 1 2^{16}-1 216−1以内的表。
基本上就够用了。