位运算

c语言位运算符

       c语言提供了六个位运算符,进行二进制计算。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。

 

1.按位与运算(&)

    (1). 运算规则     

& 0 1
0 0 0
1 0 1

    (2). 用途      ①清零     将数a与一个各位是0的数按位与

                                           例如 a&225 (225二进制数为0000 0000 1111 1111),则a的右八位清零,左八位保留

                          ②取一个数指定位的数字      若要取a的x位,则令a 和一个x位为1,其余位为0的数按位与

                                                                          例如 令a=1110    取a的第二位 则a&0100=0100

2.按位或运算符(|)

   (1). 运算规则

  | 0 1
0 0 1
1 1 1

    (2). 用途     将某位 置1      将a的x位变成1 ,则令a和一个x位为1,其余位为0的数按位或

                                                 例如 a=1010 0000   令a的左四位置1  则 a | 0000 1111 = 1010 1111

3.按位异或运算符(^)

   (1). 运算规则

  ^ 0 1
0 0 1
1 1        0     

    (2). 性质             ①交换律

                                  ②结合律    (a^b)^c=a^(b^c)

                                  ③ a^a=0      a^0=a

                                  ④自反性       a^b^b=a^0=a

     (3). 用途     ①特定位翻转       将a的几位翻转,则令a和一个翻转位为1,其余位为0的数按位异或

                                                        例如  a=10101110,使a左四位翻转,用a ^0000 1111 = 1010 0001即可得到

                             ②保留原值       将a与0异或,值不变

                             ③ 交换两数(不需要中间变量temp)   利用自反性    

                                    将a与b交换,则  a=a^b;   b=b^a;   a=a^b;

     (4). 例题                                        

                      1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一 次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?

             解法一、将所有数加起来,减去1+2+...+1000的和。(唯一的问题是,如果数列过大,则可能会导致溢出。)
            解法二、将所有的数全部异或,得到的结果与1^2^3^...^1000的结果进行异或,得到的结果就是重复数。

4.按位取反运算符(~)

     运算规则      1变为0,0变为1            如  ~1010=0101

5.左移运算符(<<)

   将一个二进制数左移若干位,高位左移溢出则舍弃,右边补0

   每左移一位,相当于该数乘2(此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况)

6.无符号右移运算符(>>)

   将一个二进制数右移若干位,低位舍弃,若是正数,高位补0,若是负数,取决于系统,补0或补1

   每右移一位,相当于该数除以2

7.复合赋值运算符

        &=     例:a &=b        相当于a=a& b

        |=       例:a |=b          相当于a=a |b

        >>=   例:a >>=b      相当于a=a>> b

       <<=    例:a<<=b       相当于a=a<< b

       ^=      例:a ^= b        相当于a=a^ b

 

 

综合例题   &和^

 

Input

第一行一个整数T,代表数据的组数(1<=T<=10),接下来T组数据,每组数据的第一行是一个整数n(1<=n<=1000000),第二行是n个整数ai(0 <= ai <= 1000000000),每两个整数之间有一个空格,题目保证有且仅有两个不同的整数出现一次,其他的整数都是出现两次。

Output

对于每组数据,输出两个整数,分别代表两个不同的整数,中间有一个空格,并且喜悦感较小的先输出。

 

Sample Input

2

6

2 2 1 1 3 4

4

1 1 3 4

Sample Output

3 4

3 4 

 

代码如下

重复利用自反性

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
long long a[1000005];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        long long x=0,num1=0,num2=0,y=1;
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&a[i]);
            x^=a[i];                   //x为只出现一次的两个数的异或值①
        }
        while(!(y & x))   y <<= 1;     //从x的最低位起找两个数第一次数不相同的位②
        for(int i=1; i<=n; i++)
        {
            if(y & a[i])     num1 ^= a[i];
            else             num2 ^= a[i];   //再次利用自反性,其余数出现两次,为0,不产生影响③
        }
        printf("%lld %lld\n",min(num1,num2),max(num1,num2));
    }
    return 0;
}
①
        }
        while(!(y & x))   y <<= 1;     //从x的最低位起找两个数第一次数不相同的位②
        for(int i=1; i<=n; i++)
        {
            if(y & a[i])     num1 ^= a[i];
            else             num2 ^= a[i];   //再次利用自反性,其余数出现两次,为0,不产生影响③
        }
        printf("%lld %lld\n",min(num1,num2),max(num1,num2));
    }
    return 0;
}

 

解释代码 

 

①将所有数异或,根据自反性,最后x的值为只出现一次的两个数(a,b)的异或值

②从最低位起求a,b第一次数不相同的位(可以先看③区分a,b的办法,可以更快理解这步的用意)

   这里假设a=1001,b=0001   则x=1000,因为异或的运算规则,同为假,所以x为0的位代表该位a,b相同,

为1则代表该位a,b不同,即在这里,a,b从低位数起,第四位不同。

    利用这个结论,从最低位起让x&1       

   while(!(y & x))        y <<= 1;                           y最初为1,即0001

    x=1000 & 0001  最低位相同,结果为0,逻辑非后执行循环,y左移一位,即y=0010

    接着 x  1000 & 0010  ,第二位相同,同样y左移一位,y=0100

    再按位与,第三位也相同,y再左移一位,y=1000

    此时 x  1000 & 1000,结果为1,退出循环,则找出从最低位数起第一次数不相同的位是第四位

③ 求出a,b数不相同的位后,再让所有数与y异或,该位结果无非是0或1,则可以将所有数区分到num1,num2

中,因为其余数出现两次,不管是0是1都会异或到num1或num2同一个数中,利用自反性,异或后,num1,

num2依然是0,而0不管异或几,都不变,所以就把a,b区分开了

  

      

 

 

 

 

 

 

posted @ 2018-02-08 10:37  任小喵  阅读(264)  评论(0编辑  收藏  举报