【数据结构和算法】——位运算相关基础知识

位运算相关基础知识

最近做leetcode关于位运算的题,将相关知识总结如下:

1. 基础运算
  1. 与运算

    将这2个数的二进制进行与操作, 只有当2个数对应的位都为1,该位运算结果为1,否则运算结果为0。即:1&1=1;1&0=0;0&0=0

  2. 或运算

    将这2个数的二进制进行或操作, 只要2个数对应的位有一个为1,该位运算结果为1,否则运算结果为0。即:1|1=1;1|0=1;0|0=0

  3. 取反

    就是将一个整数中位为1的变成0,位为0的变成1。即:1=0;0=1

  4. 异或

    将这2个数的二进制进行异或操作, 只要2个数对应的位相同,该位运算结果为0,否则运算结果为1。即:11=0;10=1;0^0=0

  5. 左移

    将一个数左移N位相当于将一个数乘以2^N

    将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0

    将12向左移动2位如何计算呢?12的二进制为00001100,那么左移动2位为:00110000

  6. 右移

    将一个数右移N位相当于将一个数除以2^N

    将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃

    将一个数a向右移动n位记为:a>>n。比如将12向右移动2位如何计算呢?12的二进制为00001100,那么右移动2位为:00000011,即3。 即12>>2为3

  7. 无符号右移

    不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃

    -5用二进制表示1111 1011,红色为该数标志位

    -5>>2: 1111 1011-------------->11 1 11110。

    11为标志位

    -5>>>2: 1111 1011-------------->00 1 11110。

    00为补充的0

  8. 总结基础运算

    • 按位与&:两位全为1,结果为1
      按位
    • 或|:两位有一个为1,结果为1
      按位
    • 异或^:两位一个为0,一个为1,结果为1
    • 按位取反:0->1,1->0
    • << 左移运算,向左进行移位操作,高位丢弃,低位补 0,如
      int a = 8;
      a << 3;
      移位前:0000 0000 0000 0000 0000 0000 0000 1000
      移位后:0000 0000 0000 0000 0000 0000 0100 0000
      
    1. >>右移运算,向右进行移位操作,对无符号数,高位补 0,对于有符号数,高位补符号位,如
       unsigned int a = 8;
       a >> 3;
       移位前:0000 0000 0000 0000 0000 0000 0000 1000
       移位后:0000 0000 0000 0000 0000 0000 0000 0001
      
       int a = -8;
       a >> 3;
       移位前:1111 1111 1111 1111 1111 1111 1111 1000
       移位前:1111 1111 1111 1111 1111 1111 1111 1111
      
2. 一些操作
  • 取最右边的第一个1(与)

  • a & (a – 1)

  • 异或性质

    a^0=a
    a^a=0

  • 翻转指定位(异或)

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

  • 消除最低位(取反)

    使a的最低位为0,可以表示为:a & 1。1的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为0

  • 如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算

  • 位运算实现乘除法

    数 a 向右移一位,相当于将 a 除以 2;数 a 向左移一位,相当于将 a 乘以 2

      int a = 2;
      a >> 1; ---> 1
      a << 1; ---> 4
    
  • 位运算交换(注意a和b不能一样)

    位操作交换两数可以不需要第三个临时变量,虽然普通操作也可以做到,但是没有其效率高

    //普通操作
    void swap(int &a, int &b) {
      a = a + b;
      b = a - b;
      a = a - b;
    }
       
    //位与操作
    void swap(int &a, int &b) {
      a ^= b;
      b ^= a;
      a ^= b;
    }
    
  • 判断奇偶数

      //偶数
       0 == (a & 1)
    
  • 交换符号

    交换符号将正数变成负数,负数变成正数

      	int reversal(int a) {
      	  return ~a + 1;
      	}
    

    整数取反加1,正好变成其对应的负数(补码表示);负数取反加一,则变为其原码,即正数

  • 位操作求绝对值

    整数的绝对值是其本身,负数的绝对值正好可以对其进行取反加一求得,即我们首先判断其符号位(整数右移 31 位得到 0,负数右移 31 位得到 -1,即 0xffffffff),然后根据符号进行相应的操作。

        int abs(int a) {
          int i = a >> 31;
          return i == 0 ? a : (~a + 1);
        } ```
    
    
  • 位操作高低位交换

    给定一个 16 位的无符号整数,将其高 8 位与低 8 位进行交换,求出交换后的值,如:

        34520的二进制表示:
        10000110 11011000
        
        将其高8位与低8位进行交换,得到一个新的二进制数:
        11011000 10000110
        其十进制为55430
    
      unsigned short a = 34520;
      a = (a >> 8) | (a << 8);
    
3. 题目(技巧)
  • x & (x - 1) 用于消去x最后一位的1

    • 用 O(1) 时间检测整数 n 是否是 2 的幂次

      N如果是2的幂次,则N满足两个条件:

      1.N >0

      2.N的二进制表示中只有一个1

      因为N的二进制表示中只有一个1,所以使用N & (N - 1)将N唯一的一个1消去,应该返回0

    • 计算在一个 32 位的整数的二进制表式,有多少个1

      不断使用 x & (x - 1) 消去x最后一位的1,计算总共消去了多少次即可

    • 如果要将整数A转换为B,需要改变多少个bit位

      将A和B进行异或,相同位为1,不同位为0,则转成了上题

  • 使用二进制进行子集枚举

    • 给定一个含不同整数的集合,返回其所有的子集

      思路就是使用一个正整数二进制表示的第i位是1还是0,代表集合的第i个数取或者不取

      所以从0到2n-1总共2n个整数,正好对应集合的2^n个子集

      S = {1,2,3}
      N bit Combination
      0 000 {}
      1 001 {1}
      2 010 {2}
      3 011 {1,2}
      4 100 {3}
      5 101 {1,3}
      6 110 {2,3}
      7 111 {1,2,3}
      
  • a ^ b ^ b = a

    • 只有一个数出现一次,剩下都出现两次,找出出现一次的数

      因为只有一个数恰好出现一个,剩下的都出现过两次,所以只要将所有的数异或起来,就可以得到唯一的那个数

    • 只有一个数出现一次,剩下都出现三次,找出出现一次的

      方法一:状态机

      方法二:循环(计算模3结果,或等在一起)

    • 只有两个数出现一次,剩下都出现两次,找出出现一次的

      因为a!=b!=0,所以a和b必然至少有一位不一样,不妨设最右边的1不一样,按此规则进行分组,分别异或,由于其他数出现两次,就会被异或掉,分别只剩下a和b

  • 异或表示无进位加法,加法可表示为无进位加法+进位

    • 不用加减乘除做加法

      无进位加法:异或 a

      进位:与运算后左移1 b

      (和 s )=(非进位和 n )+(进位 c)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值