Number of 1 Bits (求32位二进制数中1的)

<span style="font-size:24px;">
</span>

1.题目:

Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight).

For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011, so the function should return 3.

2.熟悉位运算:

1、&(按位与) 从概念上来讲,就是将参与运算的两个分量对应的每一位来做逻辑与运算,若两者都为真(等于1),则结果才为真(等于1)。否则都为假(等于0)。
即:1 & 1 = 1 、1&0 = 0 、0&1 = 0、0&0 = 0
这里我们先来看看那一个8位二进制的例子:
7&8 = 0000 0111 & 0000 1000 = 0000 0000 = 0
7&6 = 0000 0111 & 0000 0110 = 0000 0110 = 6

2、| (按位或) 即把参与运算的每个分量对应的每一位来做逻辑或运算,即两者都为假(为0)时,才为假(为0),否则皆为真。
即:0|0 = 0、1|0 = 1、0|1 = 1、1|1 = 1
来看看8位二进制的例子:
7|8 = 0000 0111 | 0000 1000 = 0000 1111 = 15
7|6 = 0000 0111 | 0000 0110 = 0000 0111 = 7

3、^(按位异或) 即把参与运算的每个分量对应的每一位来做异或运算,即两者相同为假,不同为真。
即:0|0 = 0、 1|0 = 1、0|1 = 1、 1|1 = 0
看下面的例子:
7^8 = 0000 0111 ^ 0000 1000 = 0000 0111 = 7
7^6 = 0000 0111 ^ 0000 0100 = 0000 0011 = 3

4、~(按位取反) 即把二进制位的每一位进行取反运算,简而言之就是1变成0,0变成1。
直接看例子:
~7 = ~0000 0111 = 1111 1000 = 248

5 >>(按位右移)把二进制位整体向右移动。
7>>1 = 0000 0111 >> 1 = 0000 0011 = 3
7>>2 = 0000 0111 >> 2 = 0000 0001 = 1
这里右移等于除了2的N次方,N为右移的位数。

6 <<(按位左移)这里就不详细说了,和右移相反。


3.了解uint8_tuint16_tuint32_t

  • a.uint8_tuint16_tuint32_t等都不是什么新的数据类型,它们只是使用typedef给类型起的别名。
  • 利用预编译和typedef可以让你最有效的维护你的代码。为了用户的方便,C99标准的C语言硬件为我们定义了这些类型,我们放心使用就可以了。

     按照posix标准,一般整形对应的*_t类型为:
    1字节     uint8_t
    2字节     uint16_t
    4字节     uint32_t
    8字节     uint64_t

  • 使用头文件要包含<stdint.h>(C99标准,VC6 不支持)


4.算法:
  • 最简单粗暴法:就是将二进制数与1与运算,判断最后一位是不是1,然后右移一位,直到数字移动完。

<span style="font-size:24px;">int hammingWeight(uint32_t n) 
{
	int weight = 0;
	while (n)
	{
		if ((n & 1) == 1)
		{
			weight++;
		}
		n = n >> 1;
	}
	return weight;
}</span>
算法说明:容易想到,但是效率较低

  • 改进:上个算法的效率低的原因是每位都要比较,当有例如0x10000000时,明明就一个1,难道也要比较那么多次?
所以我们就只想找到非零的位进行比较: 利用n&(n - 1)每次迭代总是将最右边的非零位置零,这样就可以提高效率

为奇数(n的二进制表示的末位为1): 
n:       xxxxxxxx1 
n-1:     xxxxxxxx0 
n&(n-1): xxxxxxxx0 
相当于去掉最右边的一个1。 

n为偶数且不等于0(n的二进制表示的末位为0): 
n:       xxxxx1000 
n-1:     xxxxx0111 
n&(n1-): xxxxx0000 
也是相当于去掉最右边的一个1。 

<span style="font-size:24px;">int sparse_popcnt(unsigned int n)
{
	int count = 0;
	while (n)
	{
		++count;
		n &= (n - 1);
	}
	return count;
}</span>


  • 其他算法可以看这里的大神总结
5.具体实现可能遇到的问题:
  • 如何输出十进制,八进制,十六进制数字
     cout<<"DEC:"<<dec<<n<<endl;  //十进制
     cout<<"OCT:"<<oct<<n<<endl;//八进制  
     cout<<"HEX:"<<hex<<n<<endl;//十六进制  
    注意:使用完某种方法比如十六进制后,要撤销,否则以后都按照十六进制输出
    cout << hex<<n << endl;
    cout.unsetf(ios::hex);

  • C++中无法表达二进制数,所以不要试图写个32位长的二进制数,让它认。。。。,用十六进制吧
  • VS调试的时候你想看16进制的值时候,在值右键->选择十六进制




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值