移位操作符与位操作符详解

目录

移位操作符

位操作符 

 例题

交换两个数,不用第三方变量。

单身狗问题


移位操作符


<<左移            >>后移
移位操作符的操作数只能是整数  ,移动的是的是操作数的二进制数码位置,整数在内存中存放的是补码。
这里移动的的是整数的补码,打印时是原码对的值。
左移操作符:技巧:左边抛弃,右边补零

int main()
{
	int a = 3;
	int c = a << 1;
	printf("%d", a);//3
	printf("%d", c);//6


	int d = -3;
	int e = d << 1;
	printf("%d", e);//-6
	return 0;
}

如图:

 右移操作符
右移分两种,1.逻辑移位   左边用零补充,右边丢弃。2.算术移位。左边用该值的符号位填充,右边丢弃
移位采用算术右移还是逻辑右移取决于编译器.
在vs采用的是算术右移

int main()
{
	int a = -5;
	int b = a >> 1;
	printf("%d", b);//-3
	return 0;
}

需要值得注意的是,一个数的二进制位最多时三十二位,移位操作注意其移位大小。

位操作符 

位操作符共有三个:& (按位与)              |(按位或)                 ^(按位异或)

对于他们的操作数,也是整数。

int main()
{
	int a = 3;
	int b = -5;
	int c = a & b;//按位与 对应二进制位同真为真,有一个为假就是假      1为真,0为假
	printf("%d", c);//3
	int d = a | b;//按位或  对应的二进制位同假为假,有一个真为真
	printf("%d", d);//-5
	int e = a ^ b;//按位异或,对应的二进制位相同为假,不同为真
	printf("%d", e);//-8   
}

如图:

注意的一点是:

0^a = a
3^3^5 = 5
3^5^3 = 5
异或是支持交换律的

 例题

交换两个数,不用第三方变量。

int main()
{
	int a = 3;
	int b = 5;
	
	printf("交换前:a=%d b=%d\n", a, b);
	
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;

	printf("交换后:a=%d b=%d\n", a, b);

	return 0;
}

当然这里除了运用按位异或。还可以用

int main()
{

    a = a + b;
	b = a - b;
	a = a - b;
	printf("交换后:a=%d b=%d\n", a, b);
}

单身狗问题

给一组数,在这里里面,有两个数字只出现一次,其他数数字都是成对出现的,找出只出现一次的两个数字
1 2 3 4 5 1 2 3  4 6

解题思路:所有的数字异或在一起,因为相同的二进制位异或之后是零,零和一个数异或是他本身。

而这里我们要找两个只出现一次的数,所以这里需要对数进行分组,使得每一组只有一个”单生狗“数,之后再进行异或操作。那麽如何分组呢?

在这里单生狗数是 5和6 ,我们可以发现5与6异或之后的结果是0 1 1,他的二进制位最后一位是1,那我们就按每个数二进制位最后一位是否是1来分组。

1 0 1 - 5
1 1 0 - 6
0 1 1
所以在此之前所有的数异或之后,我们去寻找最后该结果的二进制位哪一位是1,标记该位置。遍历二进制是从后往前的。之后再将每一个数右移至该位置,按位与1判断是否为0,为1则说明该位置的二进制位是0分一组,将该组数异或在一起,为零说明二进制位是1分为一组,将该组数异或在一起,即可以求得该单身狗数。

首先我们要对数进行分组,假设有数组的元素是:1,2,3,4,5,1,2,3,4,6

我们按它的二进制位最后一位是否为1进行分组:

第一组:
 最低位是1的数字:1 1 3 3 5

第二组:
 最低位是0的数字:2 2 4 4 6
在这里,我们也可以以它的倒数第二位是否为1进行分组

第一组:
 倒数第二位是1的数字:6 2 2 3 3

第二组:
倒数第二位是0的数字:1 1 4 4 5
 

void find_single_dog(int arr[], int sz, int* sd1, int*sd2)
{
	//1. 把所有的数字异或在一起
	int ret = 0;
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		ret ^= arr[i];
	}
	//2. 计算ret的二进制中哪一位是1
	int pos = 0;
	for (i = 0; i < 32; i++)//总共32位二进制位
	{
		if (((ret >> i) & 1) == 1)
		{
			pos = i;
			break;
		}
	}
	//3. 分组异或
	for (i = 0; i < sz; i++)
	{
		if (((arr[i] >> pos) & 1) == 1)
		{
			*sd1 ^= arr[i];
		}
		else
		{
			*sd2 ^= arr[i];
		}
	}
}

int main()
{
	int arr[] = { 1,2,3,4,5,1,2,3,4,6};

	int sz = sizeof(arr) / sizeof(arr[0]);
	int x = 0;
	int y = 0;
	find_single_dog(arr, sz, &x, &y);
	printf("%d %d\n", x, y);
	return 0;
}

int main()
{

	char arr[10] = { 0 };
	sprintf(arr, "%d", 1234);
	printf("%s\n", arr);//1234
	return 0;
}

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜求佬带

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值