• 各种位运算


    位运算的操作数必须是整数,当二元位运算的操作数是不同类型的整数时,也会自动进行类型转换。

    n&(n-1)作用:将n的二进制表示中的最低位为1的改为0,先看一个简单的例子: n = 10100(二进制),则(n-1) = 10011 ==》n&(n-1) = 10000 可以看到原本最低位为1的那位变为0。 弄明白了n&(n-1)的作用,那它有哪些应用? 1. 求某一个数的二进制表示中1的个数 while (n >0 ) { count ++; n &= (n-1); }

    2. 判断一个数是否是2的方幂 n > 0 && ((n & (n - 1)) == 0 )

    3. 计算N!的质因数2的个数。 容易得出N!质因数2的个数 = [N / 2] + [N / 4] + [N / 8] + .... 下面通过一个简单的例子来推导一下过程:N = 10101(二进制表示) 现在我们跟踪最高位的1,不考虑其他位假定为0, 则在 [N / 2] 01000 [N / 4] 00100 [N / 8] 00010 [N / 8] 00001 则所有相加等于01111 = 10000 - 1 由此推及其他位可得:(10101)!的质因数2的个数为10000 - 1 + 00100 - 1 + 00001 - 1

    = 10101 - 3(二进制表示中1的个数)

    推及一般N!的质因数2的个数为N - (N二进制表示中1的个数)

    目前看到只有这些应用,但只要理解了n&(n-1)的原理及作用,在碰到相关问题时也会比较容

    易解决。

    4.线段树中lowbitn&(-n)表示最后一个1的基数

    5.按位与运算通常用来将某变量中的某些位清0或保留某些位不变。
    例如,如果需要将int型变量n的低8位全置成0,而其余位不变,则可以执行:
    n = n & 0xffffff00;
    也可以写成:
    n &= 0xffffff00;
    如果n是short类型的,则只需执行:
    n &= 0xff00;
    如何判断一个int型变量n的第7位(从右往左,从0开始数)是否是1 ?
    只需看表达式 “n & 0x80”的值是否等于0x80即可

    6.按位或运算符“|”是双目运算符。
    功能:将参与运算的两操作数各对应的二进制位进行或操作,只有对应的两个二进位都为0时,结果的对应二进制位才是0,否则为1。
    例如:表达式“21 | 18 ”的值是23(即二进制数10111)。
    按位或运算通常用来将某变量中的某些位置1或保留某些位不变。
    例如,如果需要将int型变量n的低8位全置成1,而其余位不变,则可以执行:
    n |= 0xff;

    7.按位异或运算符“^”是双目运算符。
    功能:将参与运算的两操作数各对应的二进制位进行异或操作,即只有对应的两个二进位不相同时,结果的对应二进制位才是1,否则为0。
    例如:表达式“21 ^ 18 ”的值是7(即二进制数111)。
    异或运算的特点
    如果 a^b=c,那么就有 c^b = a以及c^a=b。
    此规律可以用来进行最简单的加密和解密

    用途:
    使特定位翻转(与0异或保持原值,与1异或取反)
    例如:要使 01111010 低四位翻转:
    0 1 1 1 1 0 1 0
    (^) 0 0 0 0 1 1 1 1
    0 1 1 1 0 1 0 1
    由于异或运算的自反性和满足交换律、结合律,常常被用于一些技巧性较强的应用中.

    void inplace_swap(int* x, int* y)
    {
    *y = *x ^ *y;
    *x = *x ^ *y;
    *y = *x ^ *y;
    }


    Q:1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次.每个数组元素只能访问一次,设计一个算法,将它

    找出来;不用辅助存储空间
    方法一:
    将1001个数加起来,再减去1+2+3+…+1000,不过这种方法不通用,容易溢出。
    方法二:
    将1001个数异或,然后和1^2^3^…^1000的结果进行异或,最后的结果就是要求的数。(a^a=0,0^a=a)


    google面试题的变形:一个数组存放若干整数,一个数出现奇数次,其余数均出现偶数次,找出这个出现奇数次的数?
    解法有很多,但是最好的和上面一样,就是把所有数异或,最后结构就是要找的,原理同上!

    找出数组中唯一不重复的元,数组可以很大。(和奇数次一样)


    8.按位非运算符“~”是单目运算符。
    其功能是将操作数中的二进制位0变成1,1变成0。
    例如,表达式“~21”的值是无符号整型数 0xffffffea,
    而下面的语句: printf("%d,%u,%x",~21,~21,~21);(无符号时,直接加权加和)
    输出结果就是:-22,4294967274,ffffffea

    9.例如,常数9有32位,其二进制表示是: 0000 0000 0000 0000 0000 0000 0000 1001
    因此,表达式“9<<4”的值,就是将上面的二进制数左移4位,得: 0000 0000 0000 0000 0000 0000 1001 0000 即为十进制的144。
    实际上,左移1位,就等于是乘以2,左移n位,就等于是乘以2n。而左移操作比乘法操作快得多。
    特别注意:有符号数的左移溢出情况。

    10.实际上,右移n位,就相当于左操作数除以2n,并且将结果往小里取整。

    11.

    1<<n=2^n;n<<1(2*n)
    有两个int型的变量a和n(0 <= n <= 31),
    要求写一个表达式,使该表达式的值和a的第n位相同。

    返回结果0或者1,不是那一位的权值,a & (1 << n )是a的第n位的权值;
    结果:(a & (1 << n )) >> n

    12.检测一个无符号数是否为2^n-1(^为幂): x&(x+1),或者(x+1)%2,前者是的话返回0,否则返回x,测试了下有符号的也可。
    将最右侧0变为1:x | (x+1),相反的是x&(x-1)。


    13.二进制进补码运算:
    -x = ~x + 1 = ~(x-1)
    ~x = -x-1
    -(~x) = x+1
    ~(-x) = x-1
    x+y = x - ~y - 1 = (x|y)+(x&y)
    x-y = x + ~y + 1 = (x&~y)-(~x&y)
    x^y = (x|y)-(x&y)(异或)
    x|y = (x&~y)+y
    x&y = (~x|y)-~x
    x==y: ~(x-y|y-x)
    x!=y: x-y|y-x
    x< y: (x-y)^((x^y)&((x-y)^x))
    x<=y: (x|~y)&((x^y)|~(y-x))
    x< y: (~x&y)|((~x|y)&(x-y))//无符号x,y较
    x<=y: (~x|y)&((x^y)|~(y-x))//无符号x,y较

  • 相关阅读:
    Java基础知识:正则表达式
    NodeJs 中 将表单数据转发到后台
    单片机的远程升级
    一些开源协议
    物联网的一些例子
    python一些开源特色库
    qt练习
    网页编程学习笔记
    PCB相关
    工业控制系统
  • 原文地址:https://www.cnblogs.com/hxsyl/p/2663752.html
Copyright © 2020-2023  润新知