class Solution {
public:
uint32_t reverseBits(uint32_t n) {
n = (n & 0xaaaaaaaa) >> 1 | (n & 0x55555555) << 1;
n = (n & 0xcccccccc) >> 2 | (n & 0x33333333) << 2;
n = (n & 0xf0f0f0f0) >> 4 | (n & 0x0f0f0f0f) << 4;
n = (n & 0xff00ff00) >> 8 | (n & 0x00ff00ff) << 8;
n = n >> 16 | n << 16;
return n;
}
};
这个函数旨在将32位无符号整数 n
的比特位进行翻转。下面是各个步骤的详细说明:
-
交换所有相邻的比特位
n = (n & 0xaaaaaaaa) >> 1 | (n & 0x55555555) << 1;
在这一步,我们想要交换每一对相邻的比特位。
0xaaaaaaaa
是一个掩码,它在32位表示中,其二进制形式为10101010 10101010 10101010 10101010
,它选中原整数中的所有奇数位 (1-based)。0x55555555
是另一个掩码,它在32位表示中为01010101 01010101 01010101 01010101
,它选中原整数中的所有偶数位。当我们执行
(n & 0xaaaaaaaa) >> 1
,我们实际上是将所有奇数位向右移动1位,填充到偶数位的位置;当我们执行(n & 0x55555555) << 1
,我们将所有偶数位向左移动1位,填充到奇数位的位置。这样,原整数中所有相邻的位就被交换了。 -
交换每2位内的比特位
n = (n & 0xcccccccc) >> 2 | ((n & 0x33333333) << 2);
这一步中,我们交换每隔1位的比特位,也就是说,我们现在操作每一对位中的每4个位。类似的,
0xcccccccc
是一个掩码,二进制表示为11001100 11001100 11001100 11001100
,它选中每4个位的高两位,而0x33333333
是00110011 00110011 00110011 00110011
,它选中每4个位的低两位。当我们右移
n & 0xcccccccc
之后,我们将原整数中每组4位内的前2位移动到原来后2位的位置;同理,左移n & 0x33333333
,将每组4位内的后2位移动到原来前2位的位置,从而实现位的交换。 -
交换每4位内的比特位
n = (n & 0xf0f0f0f0) >> 4 | (n & 0x0f0f0f0f) << 4;
在这里,我们转而交换每隔3位的比特位,即我们操作每8位内的比特位。掩码
0xf0f0f0f0
二进制表示为11110000 11110000 11110000 11110000
,它选中每组8位中的前4位;0x0f0f0f0f
为00001111 00001111 00001111 00001111
,它选中每组8位中的后4位。执行这个步骤之后,每组8位中的前4位和后4位会相互交换位置。
-
交换每8位内的比特位
n = (n & 0xff00ff00) >> 8 | (n & 0x00ff00ff) << 8;
现在,我们将一组16位中的比特位进行翻转。使用掩码
0xff00ff00
,二进制表示为11111111 00000000 11111111 00000000
,选择每组16位中的前8位;0x00ff00ff
是00000000 11111111 00000000 11111111
,它选中每组16位中的后8位。这一步将每组16位中前8位与后8位交换位置。
-
交换16位块
n = n >> 16 | n << 16;
这是最终步骤,在这里,我们做一个16位的块交换。这里没有掩码,因为我们直接做一次16位的大交换:将原数的前16位移动到后16位的位置,将后16位移动到前16位的位置。
组合这些步骤,我们逐渐扩大了交换比特位的间隔距离,从最原始的相邻位一直到16位块,实现了一个完整的32位二进制数的位翻转。
时间复杂度