《算法心得》高效用法记录

值为1且最靠右的位元置为0 (如果存在): 0101 1110 => 010 1100 : x&(x-1)

值为0且最靠右的位元置为1 (如果存在): 0101 1110 => 010 1111 : x|(x+1)

将尾部的所有连续的1置为0(如果存在): 0101 0111 => 0101 0000 : x&(x+1)

将尾部的所有连续的0置为1(如果存在): 0101 1000 => 0101 1111 : x|(x-1)

将最靠右的0置为1(如果存在),且其他位元置为0: 0101 0111 => 0000 1000 :  ~x&(x+1)

将最靠右的1置为0(如果存在),且其他位元置为1: 0101 1000 => 1111 0111 : ~x|(x-1)

将尾部的连续0置为1(如果存在),且其他位元置为0: 0101 1000 => 0000 0111 : ~x&(x-1) or ~(x|-x) or (x&-x)-1

将尾部的连续1置为0(如果存在),且其他位元置为1: 0101 0111 => 1111 1000 : ~x|(x+1)

保留最右的1(如果存在),其他位元置为1: 0101 1000 => 0000 1000 :x&(-x)

最靠右的1及其右边的位元置为1,左边置为0: 0101 1010 => 0000 1111 : x^(x-1)

最靠右的0及其右边的位元置为1,左边置为0: 0101 1010 => 0000 0111 : x^(x+1)

右侧首个连续的1置为0: 0101 1100 => 0100 0000 (((x|(x-1))+1&x)  or ((x&-x)+x)&x

进阶:

求比某个数大且位元1的个数相同的数 例如 xxx0 1111 0000 => xxx1 0000 0111

令 x = xxx0 1111 0000

s = x&-x

r = s+x

y = r | ( ( x ^ r ) << 2 / s)

两数的平均数:

(x&y) + ((x^y)>>1) 下取整

(x|y)   – ((x^y)>>1) 上取整

统计位元‘1’的个数:

1.二分搜索法:

x = (x & 0x5555 5555) + ((x>>1) & 0x5555 5555)

x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)

x = (x & 0x0F0F 0F0F) + ((x>>4) & 0x0F0F 0F0F)

x = (x & 0x00FF 00FF) + ((x>>8) & 0x00FF 00FF)

x = (x & 0x0000 FFFF) + ((x>>16) & 0x0000 FFFF)

例举一个八位数:

x = 1 0 1 1 1 1 0 0  

x1 = 01 10 10 00

x2 = 0011 0010

x3 = 00000101 = 5

上述代码中有多余的与操作

可以写成如下简单代码:

int pop(unsigned x){

x = x – ((x>>1) & 0x5555 5555)

x = (x & 0x3333 3333) + ((x>>2) & 0x3333 3333)

x = (x+(x>>4)) & 0x0F0F 0F0F

x = x+(x>>8)

        x = x + (x>>16)

return x& 0x0000 003F

}

第一行中x的值是由以下公式而来:

pop(x) =  x – [x/2] – [x/4]-···-[x/2^31]

 

点赞