在做位運算相關算法題時,經常需要我們提取二進制最右邊的一位1,接下來我們就講講關於二進制最右邊一位1的操作
獲取二進制中最右邊的1
也叫lowbit算法
x&(-x)
就是這么簡潔,就能實現獲取到二進制中最右邊的 1,且其它位設置為 0。
原因:
首先在補碼表示法中,負數的補碼 = 取反 +1,這個都知道,但你可能沒發現:
取反后:最右邊的 0 的位置對應於 最右邊的 1 的位置,
而取反后 +1 ,則會把該位的1往前進位(同時該位也會恢復為0),直到遇到第一個0停止,並把此位置為1,而第一個0就恰恰對應第一個1。
所以負數的補碼則相當於將最右邊的 1 的左邊的所有位取反。
如圖
到這已經很顯然了,x 和 −x 只有一個共同點:最右邊的 1。
(其實這么說是不嚴謹的,因為最右邊的1起,該位右邊的0也是相同的,只是對操作沒影響)
因此 x & (-x) 將保留最右邊的 1。並將其他的位設置為 0。
去除二進制中最右邊的1
x & (x - 1)
同樣是這么簡潔,就可以將最右邊的 1 設置為 0。
(x - 1)代表了將 x 最右邊的 1 設置為 0,並且將較低位設置為 1。
也不難理解, x-1 等價於 x + (-1) , 而 -1二進制就是111…11,所以低位的0自然也設置成1了,那最右邊的1也設置為0,往前進位的過程則是沒規律的。
再使用與運算:則 x 最右邊的 1 就會被設置為 0。
(嚴謹地說,該操作結果是最右邊的1該位起(包括該位)的右邊的低位全部設置為0,但因為這些低位原本就是0,所以該結論描述也是正確的)
如圖
附:其實筆者覺得理解是不難的,難就難在沒見過,就不會去這么想,新的知識又增加了!位運算牛P。