奇偶位互换指对整数二进制位中偶数索引位(0、2、4…)与相邻奇数索引位(1、3、5…)交换,需用掩码和移位操作;而数组下标奇偶位置交换是相邻元素两两调换,二者对象、单位和实现方式完全不同。

什么是奇偶位互换?明确操作边界
奇偶位互换在 C++ 中常被误解为“数组下标为奇数和偶数的元素两两交换”,比如 a[0] ↔ a[1]、a[2] ↔ a[3]、a[4] ↔ a[5]……这其实是相邻位交换,不是按“位(bit)”操作。真正对整数做“奇偶位互换”,是指将一个整数的二进制表示中,第 0、2、4…(偶数索引)位与第 1、3、5…(奇数索引)位互换——例如 0b1011 → 0b0111(从右往左编号,0-indexed)。
实际开发中,95% 的需求是前者(下标奇偶位置交换),所以先确认你要的是哪一种:
- 如果目标是重排数组顺序:操作对象是
std::vector或原生数组,单位是元素 - 如果目标是位运算变换:操作对象是单个整数(如
int),单位是 bit,需掩码和移位
按数组下标奇偶位置两两交换(常见需求)
这是最常被问到的场景,即把索引 0 和 1 交换、2 和 3 交换……直到末尾。注意:若数组长度为奇数,最后一个元素不动。
- 只需遍历偶数下标,每次处理一对:
i和i+1 - 用
std::swap最安全,避免手写临时变量出错 - 别越界:循环条件必须是
i + 1 < size,不能只写i < size
for (size_t i = 0; i + 1 < vec.size(); i += 2) {
std::swap(vec[i], vec[i + 1]);
}
-
如果用原生数组,记得传入真实长度:
立即学习“C++免费学习笔记(深入)”;
void swap_adjacent(int arr[], size_t n) { for (size_t i = 0; i + 1 < n; i += 2) { std::swap(arr[i], arr[i + 1]); } } 常见错误:用
for (int i = 0; i < n; i += 2)但没检查i+1是否越界,导致未定义行为
对单个整数做二进制奇偶位互换(位级操作)
假设 32 位整数,目标是让 bit0↔bit1、bit2↔bit3……bit30↔bit31。核心思路是:
- 提取所有偶数位:用掩码
0x55555555(二进制01010101...) - 提取所有奇数位:用掩码
0xAAAAAAAA(二进制10101010...) - 偶数位左移 1 位,奇数位右移 1 位
- 用
|合并
uint32_t swap_odd_even_bits(uint32_t x) {
const uint32_t even_mask = 0x55555555;
const uint32_t odd_mask = 0xAAAAAAAA;
return ((x & even_mask) << 1) | ((x & odd_mask) >> 1);
}
- 注意:必须用无符号类型(如
uint32_t),否则右移可能算术扩展,破坏结果 - 掩码长度要匹配整数位宽;64 位系统可用
0x5555555555555555ULL - 这个函数不关心数组,只处理单个整数;若要批量处理数组,需对每个元素调用它
容易被忽略的边界和陷阱
- 数组为空或只有一个元素时,
swap_adjacent 循环不执行,没问题;但手写循环时若没用 i + 1 < n 判断,可能访问 arr[1] 导致崩溃
- 使用
std::vector::size() 返回 size_t(无符号),若错误写成 i <= vec.size() - 2,当 vec.size() == 0 时会整数下溢成极大值,循环失控
- 位操作版本对负数直接使用
int 输入是危险的;务必先转成对应宽度的无符号整数
- 没有“通用模板”能同时安全处理任意容器和任意位宽——选择取决于你真正想动的是内存布局还是二进制模式
swap_adjacent 循环不执行,没问题;但手写循环时若没用 i + 1 < n 判断,可能访问 arr[1] 导致崩溃std::vector::size() 返回 size_t(无符号),若错误写成 i <= vec.size() - 2,当 vec.size() == 0 时会整数下溢成极大值,循环失控int 输入是危险的;务必先转成对应宽度的无符号整数位级交换和索引交换解决的是完全不同的问题,混用会导致结果完全不对。动手前,先用纸笔写两个例子,验证你理解的操作目标是否和需求一致。


















