剑指offer笔试面试题之——位运算

位运算

位运算是把数字用二进制表示之后,对每一位上0或者1的运算。

位运算总共只有五种运算:与、或、异或、左移和右移,运算规律总结如下:

与(&):     0&0 = 0;   1&0 = 0;     0&1 = 0;     1&1 = 1.

或(|):     0|0 = 0;   1|0 = 1;     0|1 = 1;     1|1 = 1.

异或(^):   0^0 = 0;   1^0 = 1;     0^1 = 1;     1^1 = 0.

左移运算符m << n表示把m左移n位。左移的时候,最左边的n为将被丢弃,同时在最右边补上n个0。比如:00001010<<2 = 00101000,00001010<<3 = 01010000。

右移运算符m << n表示把m右移n位。左移的时候,最左边的n为将被丢弃。但右移时有两种情况:第一,数字是一个无符号数值,则用0填补最左边的n位;第二,

数字是一个有符号数值,则用符号数位填充最左边的n位,即若数字原先是正数,则右移之后在最左边补n个0,若数字原先是负数,则右移之后在最左边补n个1。

比如:00001010>>2 = 00000010    10001010>>3 = 11110001


题目:实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位1。因此输入9,该函数输出2。

常规解法:

把n和1做与运算,判断n的最低位是不是为1。接着把1左移一位得到2,再和n做与运算,就能判断n的次低位是不是1……这样反复左移,每次都能判断

n的其中一位是不是。

#include<iostream>
using namespace std;
int Numberof1(int n)
{
	int count = 0;
	unsigned int flag = 1;
	while(flag)
	{
		if(n & flag)
			count++;
		flag = flag << 1;
	}
	return count;
}
int main()
{
	int a;
	cout<<"a = ";
	cin>>a;
	Numberof1(a);
	cout<<a<<" 的二进制中有 "<<Numberof1(a)<<" 个1."<<endl;
}

输出:

a = 9
9 的二进制中有 2 个1.
Press any key to continue

给面试官带来惊喜的解法:

把一个整数减去1,都是把该整数最右边的1变成0,如果它的后面还有0 的话,把它后面的所有0都变成1,而把它左边所有位都保持不变。接下来把这个整数和

它减去1的结果做与运算,相当于把它最右边的1变成0。例如:12(1100)减去1位11(1011)。在把1100和1011做与运算,结果得到1000.在把1000减1,得0111,把1000与0111做与运算的0000即此时为0,进行了两次与运算count为2,说明12(1100)中有两个1。

int Numberof2(int n)
{
	int count = 0;
	while(n)
	{
		++count;
		n = (n-1)&n;
	}
	return count;
}
int main()
{
	int a;
	cout<<"a = ";
	cin>>a;
//	Numberof1(a);
	Numberof2(2)
//	cout<<a<<" 的二进制中有 "<<Numberof1(a)<<" 个1."<<endl;
	cout<<a<<" 的二进制中有 "<<Numberof2(a)<<" 个1."<<endl;
}

相关题目:

1.用一条语句判断一个整数是不是2的整数次方。一个整数如果是2的整数次方,那么它的二进制表示中有且只有一位是1,而其他所有位都是0.(把这个整数减去

1之后再和它自己做与运算,这个整数中唯一的1就会变成0。即只能做一次与运算count = 1)

int Numberof(int n)
{
	int count = 0;
	while(n)
	{
		++count;
		n=(n-1)&n;
	}
	if(count =1)
		return true;
}
int main()
{
	int n;
	cout<<"整数n是否为2的整数次方"<<"n = ";
	cin>>n;
	Numberof(n);
	cout<<"count = "<<Numberof(n)<<" 整数n是2的整数次方。"<<endl;
}

2.输入两个整数m, n计算需要改变m的二进制表示中的多少位才能达到n。比如:10的二进制1010,13的二进制1101,需要改变1010中的3位才能得到1101,。

(分为两步:第一,求这两个数的异或;第二,统计异或结果中1的位数,1的位数即为需要改变的位数。)

int Numberof3(int m, int n)
{
	int count = 0;
	int a = m^n;
	while(a)
	{
		++count;
		a = (a-1)&a;
	}
	return count;

}
int main()
{
	int b,c;
	cin>>b>>c;
	Numberof(b,c);
	cout<<Numberof(b,c)<<endl;
}

3.实现对一个8bit数据(unsigned char类型)的指定位(例如第n位)置0或者置1操作,并保持其他地位不变。

函数原型:void set_bit(unsigned char *p_data, unsigned char position, bool flag)

函数参数说明:

P_data是指定的源数据,position 是指定位(其值范围1~8);flag表示是置0还是1操作,true:置1,flase:置0.

#include<stdio.h>
void bit_set(unsigned char *p_data,unsigned char position,int flag) 
{ 
    unsigned char a=1; 
    a=a<<(position-1); 
    if(flag==1) 
	{ 
       *p_data=*p_data|a; 
	} 
    if(flag==0) 
	{ 
        a=~a; 
        *p_data=*p_data&a; 
	} 
} 
int main()
{
	unsigned char c = 10 ;
	bit_set(&c, 3, 1);
	printf("%d\n",c);
	return 0;
}





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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值