📅  最后修改于: 2023-12-03 15:00:02.537000             🧑  作者: Mango
在解决一些算法问题时,经常会遇到需要计算一个数在二进制表示下有多少个1的情况。这个问题被称为计算二进制中1的个数(Count Bits)。
本文将介绍几种常见的方法来实现计算二进制中1的个数的功能,并给出C++代码实现。
这种方法的思路是将n的每一个二进制位和1进行按位与运算,判断这一位是否为1。如果是,计数器加1。然后将n循环右移一位,继续进行上述操作,直到n变为0为止。
int countBits1(unsigned int n) {
int count = 0;
while (n) {
if (n & 1) {
count++;
}
n >>= 1; // 循环右移
}
return count;
}
需要注意的是,n在右移的过程中,最高位会自动补0,所以无需担心死循环的问题。
这种方法的思路是利用位运算的技巧,循环将n的最后一个1变为0,并记录变化的次数,直到n变为0为止。
实现这种方法的一个常见的技巧是n & (n-1)会将n的最后一个1变成0。比如,对于n = 1011010,n-1 = 1011001,n & (n-1) = 1011000。也就是说,n中最后一个1变成了0。
int countBits2(unsigned int n) {
int count = 0;
while (n) {
n &= (n-1); // 将n的最后一个1变成0
count++;
}
return count;
}
这种方法的时间复杂度为O(k),其中k为n的二进制中1的个数。
这种方法的思路是预先计算出0到255中每一个数在二进制中1的个数,并将其存储在一个大小为256的数组中。然后,将n按8位一组进行分组,每组中每个字节的二进制表示最多只有8位,因此只需要在数组中查表即可快速得到每个字节中1的个数,并将它们累计起来。
int countBits3(unsigned int n) {
const int BITS_COUNT[256] = {
// 计算0~255中每个数的二进制中1的个数
#define B2(n) n, n+1, n+1, n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
B6(0), B6(1), B6(1), B6(2)
};
int count = 0;
unsigned char *p = (unsigned char *)&n; // 将n的地址转换为指向字符型的指针
for (int i = 0; i < sizeof(unsigned int); i++) {
count += BITS_COUNT[p[i]]; // 查表并累计
}
return count;
}
需要注意的是,使用这种方法时,需要考虑不同机器的字节序问题。比如,Intel处理器是小端字节序,因此在我们的代码中p[0]表示的是n的低字节,p[sizeof(int)-1]表示的是n的高字节。如果我们需要在另一种字节序的机器上运行这个代码,需要对数组做一些调整。
这种方法结合了上述两种方法的优点:使用查表法处理每个字节,同时使用位运算技巧计算每个字节中1的个数。
int countBits4(unsigned int n) {
const int BITS_COUNT[256] = {
// 计算0~255中每个数的二进制中1的个数
#define B2(n) n, n+1, n+1, n+2
#define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
#define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
B6(0), B6(1), B6(1), B6(2)
};
int count = 0;
unsigned char *p = (unsigned char *)&n; // 将n的地址转换为指向字符型的指针
for (int i = 0; i < sizeof(unsigned int); i++) {
count += BITS_COUNT[p[i]]; // 查表并累计
}
return count;
}
这种方法的时间复杂度为O(k),其中k为n的二进制中1的个数。
在本文中,我们介绍了四种计算二进制中1的个数的方法,并给出了C++代码实现。这些方法各有优缺点,具体选择哪一种方法要根据具体情况来定。
因为计算二进制中1的个数是一个常见的问题,在实际编程中也会经常用到。掌握这些方法可以帮助我们更快、更准地回答这种问题,提高我们的编程效率。