zoukankan      html  css  js  c++  java
  • acm算法模板(3)

    位  运  算

    程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。运位算包括位逻辑运算和移位运算,位逻辑运算能够方便地设置或屏蔽内存中某个字节的一位或几位,也可以对两个数按位相加等;移位运算可以对内存中某个二进制数左移或右移几位等。

    计算机内部是以补码形式存放数值的。C语言提供了六种位运算

     位运算符及含义

    位 运 算 符

    含   义

    举   例

    &(and)

    按位与

    a&b

    |(or)

    按位或

    a|b

    ^(xor)

    按位异或

    a^b

    ~(not)

    按位取反

    ~a

    << (shl)

    左移

    a<<1

    >> (shr)

    右移

    b>>2

    位逻辑运算规则

    a

    b

    a&b

    a|b

    a^b

    ~a

    ~b

    0

    0

    0

    0

    0

    1

    1

    0

    1

    0

    1

    1

    1

    0

    1

    0

    0

    1

    1

    0

    1

    1

    1

    1

    1

    0

    0

    0

    假设ab为整型的数据,并且设a=15(等于二进制数00000000 00001111)b=80(等于二进制数 00000000 01010000)

    a的补码:00000000 00001111

       b的补码:00000000 01010000

                ————————

    a&b:  00000000 00000000   a&b=0x0

    a|b : 00000000 01011111   a|b=0x5f

    a^b : 00000000 01011111   a^b=0x5f

    ~a  : 11111111 11110000    ~a=0xfff0

    位运算应用口诀 

    清零取反要用与,某位置一可用或

    若要取反和交换,轻轻松松用异或

    1.“按位与运算符&

    运算规则:参加运算的两个运算量,如果两个数相应位的值都是1,则该位的结果值为1,否则为0。即:0 & 0 =00 & 1 =01 & 0 =01 & 1 =1

    (1)将某些二进制位屏蔽掉(保留一个数据中的某些位)。

    如果要使整数k的低四位置零,保留其它位。用位与运算即可,将的高字节与0相与,低字节与1相与;

    代码如下:unsigned int_set(unsigned int k)

    {k=k&0x1110;

    Return(k);}

    例】00101010 01010010&11111111 11110000=00101010 01010010

    结论:任何二进制位与0能实现置0;与1保持原值不变

    2判断一个数据的某一位是否为1

    如判断一个整数a(2个字节)的最高位是否为1,可以设一个与a同类型的测试变量testtest的最高位为1,其余位均为0,即int test=0x8000

    【例】   0100010011111110&1000000000000000=0 说明最高位为0

         1100010011111110&1000000000000000=1000000000000000 说明最高位为1

    例如一个数 and 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数.

    2.“按位或运算符|

    常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)

    运算规则:参加运算的两个运算量,如果两个数相应位的值都是0,。即:0 | 0 =00 | 1 =11 | 0 =11 | 1 =1

    把一个数据的某些位置为1

    如果把a的第10位置为1,而且不要破坏其它位,可以对ab进行按位或运算,其中b的第10位置为1,其它位置为0,即int b=0x400

    【例】00100000 01010010|00000010 00000000=00100010 01010010

    3.“按位异或运算符^

     运算规则:参加运算的两个运算量,如果两个数的相应位的值不同,则该位的结果值为1,否则为0。即:0 ^ 0 =00 ^ 1 =11 ^ 0 =11 ^ 1 =0

    应用举例:

    1把一个数据的某些位翻转,即1变为00变为1

    如要把a的奇数位翻转,可以对ab进行按位异或运算,其中b的奇数位置为1,偶数位置为0,即int b=0xaaaa

    【例】a的补码:00000000 01010010

    b的补码: 01010101 01010101

          ^   -------------------

    结果的补码:  01010101 00000111

    2交换两个值,不用临时变量。

    【例】a=3b=4。想将ab的值互换,可以用以下三条赋值语句实现:

    a=a^b;即:a=3^4=7(0011^0100=0111)

    b=b^a;即:b=4^7=3(0100^0111=0011)

    a=a^b;即:a=7^3=4(0111^0011=0100)

    不用temp交换两个整数
    void swap(int x , int y)
    {
    x ^= y;
    y ^= x;
    x ^= y;
    }

    编写对字符串进行密钥匙异或加解密程序

    有了加密程序(a^b),相应的就应该有解密程序。解密程序是加密程序的逆过程,这里的加密和解密程序是完全相同的,原因是(a^b^b=a。大家自己分析,并完善该实训。           }

    4.“按位取反运算符~

    移位运算符:

    左移、右移运算实现将一个数的各个二进制位向左向右移若干位。

    1.左移运算符<<

    运算规则:对运算符<<左边的运算量的每一位全部左移右边运算量表示的位数,右边空出的位补0

    【例】a<<2表示将a的各位依次向左移2位,a的最高2位移出去舍弃,空出的低2位以0填补。

    例:char a=0x21

    a<<2的过程 0010 0001〈〈2 = 1000 0100即 a<<2的值为0x84。

    左移1位相当于该数乘以2,左移n位相当于该数乘以2n。

    乘法运算转化成位运算 (在不产生溢出的情况下)
    a * (2^n) 等价于 a<< n        

    2. 右移运算符>>

    运算规则:对运算符>>左边的运算量的每一位全部右移右边运算量表示的位数,右边低位被移出去舍弃掉,空出的高位补0还是补1,分两种情况:

    (1)对无符号数进行右移时,空出的高位补0。这种右移称为逻辑右移。

    (2)对带符号数进行右移时,空出的高位全部以符号位填补。即正数补0,负数补1。这种右移称为算术右移。

       右移1位相当于除以2,同样,右移n位相当于除以2n。

    除法运算转化成位运算 (在不产生溢出的情况下)
    a / (2^n) 等价于 a>> n
    取模运算转化成位运算 (在不产生溢出的情况下)
    a % (2^n) 等价于 a & (2^n - 1)

    循环移位的实现。

    如将一个无符号整数x的各位进行循环左移4位的运算,即把移出的高位填补在空出的低位处。

    可以用以下步骤实现:

    1)将x左移4位,空出的低4位补0,可通过表达式x<<4实现。

    2)将x的左端高4位右移到右端低4位,可通过表达式x>>(16-4)实现。由于x为无符号整数,故空出的左端补0

    3)将上述两个表达式的值进行按位或运算,即:

          y=(x<<4) | (x>>(16-4))

       x       0010 1111 0010 0001

    x<<4       1111 0010 0001 0000

    x>>(16-4)  0000 0000 0000 0010

    y          1111 0010 0001 0010

     unsigned rol ( unsigned aint n)

               {   unsigned b 

                   b=(a<<n) | (a>>(16-n)) 

                   return(b)}

    计算绝对值
    int abs( int x )
    { int y ;
     y = x >> 31 ;//二进制最高位
     return (x^y)-y ; //or: (x+y)^y 

    }

    位 段

    C语言又提供了一种数据结构,称为位域位段。所谓位域是把一个字节中的二进位划分为几个不同的区域, 并说明每个区域的位数。每个域有一个域名,答应在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。

    位段结构是指结构体成员可以是以位为单位定义存储长度的结构体。

    位段结构的定义形式如下:

                           struct 结构类型名

    {

     类型   成员 1:长度;

     类型   成员2:长度;

                                ……

    }

    其中,冒号左面的成员称为位段,它是一种特殊的结构成员,冒号右面的长度表示存储位段需要占用字节的位数。

    【例】  struct device 

            {   unsigned a1

                unsigned b2

                unsigned c4

                int x

                float y

           }  data

     定义了结构体变量data,它包含5个成员,它们分别是abcxy

    c

    b

    a

    x

    y

       1  4   2 1          16                   32

    结构变量data的内存分配情况

    位段的引用

    位段是结构体类型的某个成员,因此位端的引用同结构体成员的引用方法相同。

    如:data.a=0x01;

    data.b=0x0a;

    data.i= 12;                                                                  

       printf(“%02x,%02x,%4d”,data.a,data.b,data.c)

    输出:01,0a,12

    位段也可以用%u%o等格式符输出。

    说明:

    1.位段的数据类型必须用unsignedint类型不能用char和其它类型。有的C编译系统只允许用unsigned型。

     未完待续,,,

     

     

     

  • 相关阅读:
    设计模式面试
    Netty面试
    Nginx面试
    java后端面试
    springboot面试专题及答案
    SpringBoot整合Mybatis,TypeAliases配置失败的问题
    vscode调试html文件
    Linux性能检查命令总结[转]
    如何创建systemd定时任务
    Systemd简介与使用
  • 原文地址:https://www.cnblogs.com/jeff-wgc/p/4483378.html
Copyright © 2011-2022 走看看