关于位运算

本蒟蒻在大学的第一周,acm队发了一套习题集,其中关于位运算的题目让我想起来在高中还是oier的时候对于位运算的迷茫, 在此重新学习并整理了一些关于位运算的东西。

位运算符号总览:

在这里插入图片描述

按位与运算符(&)

运算规则:

0&0=0 0&1=0 1&0=0 1&1=1

总结:两位同时为1,结果才为1,否则结果为0。

例如:

3&5 即 0000 0011& 0000 0101 = 0000 0001,因此 3&5 的值得1。

注意:负数按补码形式参加按位与运算。

与运算的用途:

(1)清零

如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

(2)取一个数的指定位

比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。

(3)判断奇偶数

只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

按位或运算符(|)

运算规则:

0|0=0 0|1=1 1|0=1 1|1=1

总结:参加运算的两个对象只要有一个为1,其值为1。

例如:3|5即 0000 0011| 0000 0101 = 0000 0111,因此,3|5的值得7。

注意:负数按补码形式参加按位或运算。

或运算的用途:

(1)常用来对一个数据的某些位设置为1

比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

异或运算符(^)

0^0=0 0^1=1 1^0=1 1^1=0
异或运算的用途:

(1)翻转指定位

比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。

位运算的实际运用

(1):不用任何中间变量,交换两个整型变量。

void work()
{
	int a,b;
    a = a^b;
    b = b^a;
    a = a^b;
}

(2)求整形的二进制中1的个数n&(n-1)
思想:n&(n-1)能实现将最低位的1翻转。比如说n=108,其二进制表示为01101100,则n&(n-1)的结果是01101000。因此只要不停地翻转n的二进制的最低位的1,每翻转一次让计数器+1,直到n等于0时,计数器中就记录了n的二进制中1的位数。

int work()
{
    int sum =0;
    while(n)
    {
        sum++;
       n&=(n-1);
    }
    return sum;
}

PS:n&(n-1)的另外一个用处是判断n是否是2的整数次幂.

(3) 将整数二进制中右侧的连续1位串翻转成0位串,其他保持不变((x|(x-1))+1)&x
思想:x|(x-1) 使得x中最右边的1的右边的0都被1填充了;而(x|(x-1))+1 就使得x中那个连续的1位串和它右边的0位串都变成0,并且将连续的1位串的左边那位0变成了1,并保持其他位不变; (x|(x-1)+1)&x使得x中那个连续的1位串和它右边的所有位都置为0,而保持那个连续的1位串的左边保持不变,于是就实现了将最右边的连续的1位串翻转的功能。

例题

As we known, data stored in the computers is in binary form. The problem we discuss now is about the positive integers and its binary form.

Given a positive integer I, you task is to find out an integer J, which is the minimum integer greater than I, and the number of '1’s in whose binary form is the same as that in the binary form of I.

For example, if “78” is given, we can write out its binary form, “1001110”. This binary form has 4 '1’s. The minimum integer, which is greater than “1001110” and also contains 4 '1’s, is “1010011”, i.e. “83”, so you should output “83”.
Input
One integer per line, which is I (1 <= I <= 1000000).

A line containing a number “0” terminates input, and this line need not be processed.
Output
One integer per line, which is J.
Sample Input
1
2
3
4
78
0
Sample Output
2
4
5
8
83

题目大意:给一个数n,找到与n二进制中1个数一样的大于n的最小数。

暴力解法:一个个枚举当然可以,毕竟暴力出奇迹嘛,就是慢到绝望。在这里插入图片描述

利用位运算AC

     x = N&(-N);      
     t = N+x;
     ans = t | ((N^t)/x)>>2;

int x = N&(-N)

它的功能是找到N的二进制表示中最右边的1(这个1必定是N的二进制表示中最右边的连续的1位串的开始)。

int t = N+x;

该语句实现了“将连续的1位串中最左边的1向左“移动”一位”的功能,当然它带来了副作用:使得连续的1位串中其他的1没了

ans = t | ((N^t)/x)>>2;

将上面丢失的1补上,并放到最右边。

补课还满课的gcx会回来填坑的🕊🕊🕊
未完待续…

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值