lowbit
lowbit
在競賽中還是很常見的,比如樹狀陣列就必須要用 lowbit
。
lowbit
的原理是利用原碼, 反碼, 補碼的性質來獲得數字在二進位制下最低位的 \(1\)。理解了原碼,反碼,補碼,就不難理解 lowbit
了。
lowbit
程式碼如下:
inline int lowbit(int x) {
return x & -x;
}
以一個例子來理解上面的程式碼(假設你已經理解了原碼,反碼,補碼):
- 我們假設 \(n = 8\)。\(8\) 的二進位制為 : \(00001000\)。
- 對 \(8\) 取反的二進位制為:\(11110111\)。
- 再對取反 \(8\) 加一(補碼)的二進位制為:\(11111000\)。
- 進行與操作之後:\(00001000\)。
就得到了我們的 \(lowbit(8) = 8\)
highbit
這個相對來說要少見些。
顧名思義,它乾的事與 lowbit
相反,求的是數字在二進位制下最高位的 \(1\)。
其原理是將一個數二進位制下最高位的 \(1\) 及其右面的每一位都補充為 \(1\),然後把最高位右面的都減掉,剩下就是最高位的 \(1\)。程式碼如下:
int highbit(int x){
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
為什麼這樣寫呢?
我們假設 \(x\) 在二進位制下只有最高位是 \(1\),其餘位都是 \(0\)。透過 highbit
函式的第一行,我們透過右移 \(1\) 位並與原來的 \(x\) 異或,將 \(x\) 最高位往右一位填充為了 \(1\),現在總共有連續的兩個 \(1\)。接著透過第二行,可以繼續向右填充兩位,現在統共有 \(4\) 位 \(1\) 了。接下來的程式碼以此類推,我們就可以把右面全部填充為 \(1\) 了,最後 x - (x >> 1)
就可以得到我們想要的 highbit
了。
上面的函式返回值是 int
型的,如果用別的型別,可以自行調整右移位數。