位运算的奇巧淫技

位运算与进制基础

位运算符

1.在处理整形数值时,可以直接对组成整形数值的各个位进行操作。这意味着可以使用屏蔽技术获得整数中的各个位。

2.&(与)、|(或)、^(异或)、~(非/取反)。

3.>>和<<运算符将二进制位进行右移或者左移操作。

4.>>>运算符将用0填充高位;>>运算符用符号位填充高位,没有<<<运算符。

5.对于int型,1<<35与1<<3是相同的,而左边的操作数是long型时需对右侧操作数模64。

6.与:都为1结果为1;或:有一个为1结果为1,;异或:二者不同时结果为1。

在这里插入图片描述

小技巧

1.判断奇偶数:x&1=1则x是奇数,x&1=0则x是偶数。

2.获取二进制位是1还是0:x&某一个奇数之后再右移相应的位数。

3.交换两个整数变量的值。

4.不用判断语句,求整数的绝对值。

异或:可以理解为不进位加法:1+1=0,0+0=0,1+0=1。

性质

1.交换律可以交换运算因子的位置,结果不变。

2.结合律(即(a ^ b ) ^ c = = a ^ ( b ^ c ) )

3.对于任何数x,都有x ^ x = 0 , x ^ 0 = x ,同自己求异或为0,同0求异或为自己。

4.自反性A ^ B ^ B = A ^ 0 = A,连续和同一个因子做异或运算,最终结果为自己。

题解

题1:找出唯一成对的数

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

思路

连续异或,消除重复。

代码

#include <iostream>
using namespace std;
int main()
{
    int x=0,test[10]={1,2,3,4,5,6,7,8,9,7};
    for (int i = 1; i <= 9; ++i) x=x^i;
    for (int j = 0; j < 10; ++j) x=x^test[j];
    cout<<x<<endl;
    return 0;
}

题2:找出落单的那个数

一个数组里处理某一个数之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

思路

连续异或,消除重复。

代码

#include <iostream>
using namespace std;
int main()
{
    int x=0,test[11]={1,1,3,3,5,5,7,7,9,9,11};
    for (int j = 0; j < 11; ++j) x=x^test[j];
    cout<<x<<endl;
    return 0;
}

题3:二进制中1的个数

请实现一个函数,输入一个整数,输出该数二进制表示中的1的个数。
例:9的二进制表示为1001,有2位是1.

思路

1.整数x与1,然后将1循环左移32次;
2.整数x与1,然后将x循环右移32次;
3.x&(x-1)可以消掉最右边的1,直到x=0。

代码

#include <iostream>
using namespace std;
int main()
{
    int x,n=1,ans=0;
    cin>>x;
    for (int i = 0; i < 32; ++i)
        if (x&(n<<i)) ans++;
    cout<<ans<<endl;
    return 0;
}
#include <iostream>
using namespace std;
int main()
{
    int x,ans=0;
    cin>>x;
    for (int i = 0; i < 32; ++i)
        if ((x>>i)&1) ans++;
    cout<<ans<<endl;
    return 0;
}
#include <iostream>
using namespace std;
int main()
{
    int x,ans=0;
    cin>>x;
    while (x)
    {
        x=x&(x-1);
        ans++;
    }
    cout<<ans<<endl;
    return 0;
}

题4:是不是2的整数次方

用一条语句判断一个整数是不是2的整数次方。

思路

2的整数次方说明x中只有一个1,x&(x-1)可以消掉最右边的1。

代码

#include <iostream>
using namespace std;
int main()
{
    int x;
    cin>>x;
    if ((x&(x-1))==0) cout<<"yes"<<endl;
    else cout<<"no"<<endl;
    return 0;
}

题5:将整数的奇偶位互换

输入一个整数,将其二进制形式的奇偶位置数互换。

思路

一个数&(0101)×8得到的是它的所有奇数位数字,&(1010)×8得到的是它所有偶数位数字,然后分别左移和右移之后再异或一下,得到的就是奇偶位互换的数字。

代码

#include <iostream>
using namespace std;
int main()
{
    int x;
    cin>>x;
    int ji=0x55555555,ou=0xaaaaaaaa;
    int a=x&ji,b=x&ou,c=(a<<1)^(b>>1);
    cout<<c<<endl;
    return 0;
}

题6:0~1间浮点实数的二进制表示

给定一个介于0和1之间的实数,(如0.625),类型为double,打印它的二进制表示(0.101,因为小数点后的二进制分别表示0.5,0.25,0.123…)。
如果该数字无法精确地用32位以内的二进制表示,则打印“ERROR”

思路

浮点数转换为二进制的方式为乘2挪整。

代码

#include <iostream>
#include <cstring>
using namespace std;
int main()
{
    string s;
    int len=0;
    double x;
    cin>>x;
    while (x>0)
    {
        double num=x*2;
        if (num>=1.0)
        {
            s+='1';
            x=num-1;
        }
        else
        {
            s+='0';
            x=num;
        }
        len++;
        if (len>32)
        {
            cout<<"ERROR"<<endl;
            return 0;
        }
    }
    cout<<"0."<<s<<endl;
    return 0;
}

题7:出现k次与出现1次

数组中只有一个数出现了1次,其它的数都出现了k次,请输出只出现了1次的数。

思路

k个相同的k进制数做不进位加法结果为0。

原文地址:https://www.cnblogs.com/AlexKing007/p/12338453.html