一行代碼看懂奇偶判斷本質
代碼含義拆解
if (n % 2) {
// n 為奇數時執行
}
三層機制解析
| 層次 | 操作 | 說明 | 示例 (n=5) |
| 1. 模運算 | n % 2 | 取模(餘數),結果為 0 或 1(對於正數) | 5 % 2 = 1 |
| 2. 真值判斷 | if (值) | C 語言:0 為假,非 0 為真 | 1 → 真 |
| 3. 分支執行 | 執行/跳過 | 真執行花括號內,假跳過 | 執行 if 體 |
數學本質對照表
| n | n % 2 | if 判斷 | 數學含義 | 執行結果 |
| 0 | 0 | 假 | 偶數 | 跳過 |
| 1 | 1 | 真 | 奇數 | 執行 |
| 2 | 0 | 假 | 偶數 | 跳過 |
| 3 | 1 | 真 | 奇數 | 執行 |
| -1 | -1 | 真 | 奇數 | 執行 |
| -2 | 0 | 假 | 偶數 | 跳過 |
關鍵注意點
- 負數取模:C99 規定
-3 % 2 == -1(非零即真),依然正確判斷奇數
- 位運算替代:
if (n & 1) 效率更高,直接檢查最低位
- 可讀性權衡:
n % 2 != 0 更明確表達意圖,現代編譯器優化後無性能差異
完整演示程序
#include <stdio.h>
void check_parity(int n) {
printf("n = %3d: ", n);
// 方法1:模運算(標準寫法)
if (n % 2 != 0)
printf("奇數 ");
else
printf("偶數 ");
// 方法2:位運算(高性能場景)
if (n & 1)
printf("[位運算:奇] ");
else
printf("[位運算:偶] ");
// 方法3:原始 if(n%2) 寫法
if (n % 2)
printf("[if(n%%2):執行]");
else
printf("[if(n%%2):跳過]");
printf("\n");
}
int main() {
int test_cases[] = {-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5};
int n = sizeof(test_cases) / sizeof(test_cases[0]);
printf("奇偶性判斷演示:\n");
for (int i = 0; i < n; i++) {
check_parity(test_cases[i]);
}
return 0;
}
執行輸出
n = -5: 奇數 [位運算:奇] [if(n%2):執行]
n = -4: 偶數 [位運算:偶] [if(n%2):跳過]
n = -3: 奇數 [位運算:奇] [if(n%2):執行]
n = -2: 偶數 [位運算:偶] [if(n%2):跳過]
n = -1: 奇數 [位運算:奇] [if(n%2):執行]
n = 0: 偶數 [位運算:偶] [if(n%2):跳過]
n = 1: 奇數 [位運算:奇] [if(n%2):執行]
n = 2: 偶數 [位運算:偶] [if(n%2):跳過]
n = 3: 奇數 [位運算:奇] [if(n%2):執行]
n = 4: 偶數 [位運算:偶] [if(n%2):跳過]
n = 5: 奇數 [位運算:奇] [if(n%2):執行]
延伸應用:快速篩選
// 提取陣列中所有奇數
int extract_odds(int *src, int n, int *dst) {
int count = 0;
for (int i = 0; i < n; i++) {
if (src[i] & 1) // 位運算判斷奇數
dst[count++] = src[i];
}
return count;
}
// 奇偶分離(雙指針原地分區,類似快排 partition)
void partition_parity(int *arr, int n) {
int left = 0, right = n - 1;
while (left < right) {
while (left < right && (arr[left] & 1)) left++; // 找偶數
while (left < right && !(arr[right] & 1)) right--; // 找奇數
if (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}