位运算

位运算在我们编程中效率极高,所以多用位运算可以极大提高我们程序的效率。

位运算一共有五种:与、或、异或、左移、右移。
一、与、或
题目:判断一个字符串中的字符是否唯一,并且字符只包含a-z。
分析:a-z 一共26个字母,如果用位运算,只需26位即可,初始所有位设置为0,如果某个字符第一次出现,则将0变为1,如果某个字符再次出现,直接返回false,判断某个字符是否重复出现,则用到位运算中的与。
代码:

bool isUnique3(string s)
{
    int check = 0;  //把所有位初始化为0
    int len = s.length();
    for (int i = 0; i < len; i++)
    {
        int v =int( s[i] - 'a');
        if (check & (1 << v))  //如果某个字符以前出现过,位相与结果不为0
            return false;
        check |= (1 << v);   //如果某字符第一次出现,则用位或运算,将0变为1
    }
    return true;
}

总结:
通过与运算,我们可以用来判断某一个二进制位;
通过或运算,我们可以用来改变某一个二进制位。
(N-1)&N,相当于把整数N的二进制表示中最右边的1变为0

二、异或
题目:一个整形数组,只有1个数出现1次,其他数都出现2次。请找到这个出现1次的数。
分析:题目很有特点,所有数都出现2次,只有一个数出现1次,用异或可能有奇效,将所有整数进行异或处理,出现两次的整数用异或处理后变为0,最后结果即为只出现一次的数。
直接这么想可能有些难度,例2^3^3^4^4,可以看做2^(3^3)^(4^4),这样就不难理解了。
因为 X^X=0 ; 0^X=X.
代码:

int intOnly(int *a, int len)
{
    int sum = 0;
    for (int i = 0; i < len; ++i)
    {
        sum ^= a[i];
    }
    return sum;
}

总结:
X^X=0 ; 0^X=X
两个数相同,异或结果为假;
两个数不同,异或结果为真。

三、左移
左移: m<<n表示将m左移n位,左移时,最左边的n位被丢弃,同时在最右边补上n个0。例00001010<<2 = 00101000; 10001010<<3 = 01010000.
m<<n如果左移没有超过界限,则表示乘以2的n次方。无论m为整数还是负数。
若m为正数,不难理解;
若m为负数,因为在计算机内部,数字是用补码表示的,不超过界限,则m的前几位全为1,左移了以后,符号位仍为1,所以也就不难理解了。

四、右移
右移:m>>n表示将m右移n位,右移时,最右边的n位被丢弃,最左边的n位用符号位代替。
例:00001010>>2 = 00000010 ; 10001010>>3 = 11110001.

题目:实现一个函数,输入一个整数n,输出该数二进制表示中1的个数。
分析:方法一:右移整数n,因为n为整数,所以右移31次,用n和1相与32次。如果不是用32来控制循环次数,而是用while(n)来控制循环,当n为负数时,无论右移多少次,都不可能跳出循环,就会陷入死循环,因为当n为负数时,右移时左边补充的全为1。
方法二:首先把n和1进行与运算,判断n的最后一位是否为1,然后把1左移一位,再和n进行与运算,判断n的倒数第二位是否为1,依次类推……
代码:

//方法一
int NumberOf1(int n)
{
    int flag = 0;  //flag用来统计1的个数
    for (int i = 0; i < 32; ++i)
    {
        if (n & 1)
        {
            ++flag;
        }
        n = n >> 1;
    }
    return flag;
}

//方法二

int NumberOf1(int n)
{
    int flag = 0;  //统计1的个数
    unsigned int m = 1; //m左移31次,分别和n进行与运算
    for (int i = 0; i < 32; ++i)
    {
        if (n & m)
        {
            ++flag;
        }
        m = m << 1;
    }
    return flag;
}

总结:
如果要对每一位进行操作,则左移和右移将会极大简便我们的程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值