轉自:https://blog.csdn.net/wuxianglonghaohao/article/details/21602305
http://www.newhottopic.com/2014/03/20/reverse-bits/
把一個無符號整數的比特位反轉順序。
有很多種方法來實現這個。我們這里給出一個算法:通過異或運算來交換,然后用分治方法來優化它。
提示:
你怎么把第i個和第j個位置的bit給交換了呢?如果你能用異或來實現,試着給出算法。
異或交換的小技巧:
如果一共有n個bit,反轉它可以通過最少n/2次交換,最多n次交換來完成。技巧就在於實現一個交換函數swapBits(i,j),用來交換位置在i和j的兩個bit。你應該還記得異或運算:0 ^ 0 == 0, 1 ^ 1 == 0, 0 ^ 1 == 1, 和 1 ^ 0 == 1。
我們只要在第i位和第j位的bit不同時交換就行了。我們用異或來檢測這兩位bit是否相同。然后我們還需要切換這兩個位置的bit值,我們可以再次用異或來完成操作。通過異或,兩個位置的值都可以被切換了。
-
typedef unsigned int uint;
-
uint swapBits(uint x, uint i, uint j) {
-
uint lo = ((x >> i) & 1);
-
uint hi = ((x >> j) & 1);
-
if (lo ^ hi) {
-
x ^= (( 1U << i) | (1U << j));
-
}
-
return x;
-
}
-
-
uint reverseXor(uint x) {
-
uint n = sizeof(x) * 8;
-
for (uint i = 0; i < n/2; i++) {
-
x = swapBits(x, i, n-i -1);
-
}
-
return x;
-
}
(譯者注:上面的其中一行代碼:x ^= ((1U < < i) | (1U << j));是為了切換兩個位置的bit值,可以看個例子:x = 1001,–> x ^= ((1U < < 1) | (1U << 3)) –> x = 1001 ^ (1010) –> x = 0011 )
用這種異或方法來反轉bit位的時間復雜度是O(n),n是傳入的無符號整數的比特位數。
分而治之:
記得歸並排序是怎么做的吧?讓我們看一下當n=8(一字節)時是怎么樣的:
-
01101001
-
/ \
-
0110 1001
-
/ \ / \
-
01 10 10 01
-
/\ /\ /\ /\
-
0 1 1 0 1 0 0 1
第一步是交換所有奇數和偶數位置的bit。然后交換連續成對的bit,依此類推……
因此,一共只要log(n)次操作就能完成。
下面的代碼展示了一個特定的當n==32時的例子——當然,它也能很簡單的去適配當n更大時的情況。
-
uint reverseMask(uint x) {
-
assert( sizeof(x) == 4); // special case: only works for 4 bytes (32 bits).
-
x = ((x & 0x55555555) << 1) | ((x & 0xAAAAAAAA) >> 1);
-
x = ((x & 0x33333333) << 2) | ((x & 0xCCCCCCCC) >> 2);
-
x = ((x & 0x0F0F0F0F) << 4) | ((x & 0xF0F0F0F0) >> 4);
-
x = ((x & 0x00FF00FF) << 8) | ((x & 0xFF00FF00) >> 8);
-
x = ((x & 0x0000FFFF) << 16) | ((x & 0xFFFF0000) >> 16);
-
return x;
-
}
小記:
這不是反轉bit位的唯一方法,也不是效率最高的。你想要探索更多關於反轉bit位的算法/靈感,請訪問這里:
Bit Twiddling Hacks(譯者注:該鏈接里真的很多好東東)。
英文原文在
這里。