位元運算是系統程式、嵌入式開發、演算法優化的核心利器。本文整理七大經典位元運算實戰技巧,涵蓋計數、提取、判斷、反轉、平均、找單一、異或應用,附完整 C 程式碼與原理解析。
int count_one_bits(unsigned int value) {
int count = 0;
while (value) {
value &= (value - 1); // 清除最低位的 1
count++;
}
return count;
}
原理:`value - 1` 會將最低位的 1 變 0,低位 0 變 1;`&` 運算恰好清除該 1。每次迴圈消除一個 1,迴圈次數 = 1 的個數。時間複雜度 O(k),k 為 1 的個數。
void print_odd_even_bits(int num) {
int odd[16], even[16];
// 奇數位(bit 1,3,5... 即第 0,2,4... 索引)
for (int i = 0, j = 0; j < 32; i++, j += 2)
odd[15-i] = (num >> j) & 1;
// 偶數位(bit 0,2,4... 即第 1,3,5... 索引)
for (int i = 0, j = 1; j < 32; i++, j += 2)
even[15-i] = (num >> j) & 1;
printf("奇數位(高->低): ");
for (int i = 0; i < 16; i++) printf("%d ", odd[i]);
printf("\n偶數位(高->低): ");
for (int i = 0; i < 16; i++) printf("%d ", even[i]);
printf("\n");
}
※ 注意:位元索引通常從 0 起算(LSB 為第 0 位),文中「奇數位」實為索引為偶數的位元。
// 假設排名範圍 1~5,對應 bit 0~4
int ranks[5] = {a, b, c, d, e};
int mask = 0;
for (int i = 0; i < 5; i++)
mask |= (1 << (ranks[i] - 1)); // 設定對應位
// 檢查是否連續:連續 n 個 1 形式為 (1<
技巧四:計算兩數二進制不同位數(漢明距離)
int different_bits(int m, int n) {
int xor = m ^ n; // 不同位為 1
return count_one_bits(xor); // 復用技巧一
}
異或完美識別差異位,配合計數 1 的演算法極為高效。
技巧五:無符號整數二進制位元反轉
unsigned int reverse_bits(unsigned int num) {
unsigned int ret = 0;
for (int i = 0; i < 32; i++) {
ret <<= 1; // 左移騰出最低位
ret |= (num >> i) & 1; // 取 num 第 i 位填入
}
return ret;
}
從低位到高位依次取出,構建反轉後的數值。可優化為查表法(8-bit 查表 4 次)提升速度。
技巧六:無溢出計算兩數平均值
int average(int a, int b) {
// (a & b) 保留共同的 1(進位部分)
// (a ^ b) >> 1 計算不產生進位的平均
return (a & b) + ((a ^ b) >> 1);
}
原理證明:`a + b = (a ^ b) + 2*(a & b)` → `(a+b)/2 = (a&b) + ((a^b)>>1)`。完全避免 `a+b` 溢出。
技巧七:找出陣列中唯一出現一次的數字(其餘皆出現兩次)
int find_single(int arr[], int size) {
int result = 0;
for (int i = 0; i < size; i++)
result ^= arr[i]; // 相同數異或為 0,0 異或 x = x
return result;
}
異或性質:`x ^ x = 0`,`x ^ 0 = x`,滿足交換律與結合律。成對數字抵消為 0,單獨者保留。
綜合測試主程式
int main() {
printf("count_one_bits(15)=%d\n", count_one_bits(15)); // 4
print_odd_even_bits(0b10101010);
int ranks[] = {1,2,3,4,5};
// ... 測試其他函式
return 0;
}
總結速查表
需求 核心運算 關鍵性質
計數 1 `x &= x-1` 每次清除最低位 1
提取位 `(x>>k)&1` 右移歸位 + 遮罩
設定位 `x |= (1<或運算置 1
清除位 `x &= ~(1<與運算置 0
翻轉位 `x ^= (1<異或翻轉
檢測 2 的冪次 `x && !(x & (x-1))` 僅有一個 1
無溢出平均 `(a&b)+((a^b)>>1)` 分解進位與非進位
找單一數 `xor` 累積 成對抵消
結語
位元運算看似晦澀,實則是電腦最原生的語言。熟練掌握上述技巧,能在演算法競賽、系統優化、硬體驅動、加密演算等領域寫出極致高效的程式碼。建議多動手實驗,觀察二進制變化,建立直覺理解。