zoukankan      html  css  js  c++  java
  • 位运算计算与位运算应用

    位运算包括与,或,取反,异或,左移,右移等。

    一 位运算计算

    1 与运算:&

      操作符&将2个数的二进制位进行与操作,2个数对应的位都为1,运算结果为1;否则运算结果为0。

    比如 6&8,6的二进制为:0110   8的二进制为:1000。所以6&8 = 0000 = 0

    2 或运算:|

      操作符|将2个数的二进制位进行或操作,2个数对应的位有一个为1,运算结果为1;否则运算结果为0。

    比如 6&8,6的二进制为:0110   8的二进制为:1000。所以6&8 = 1110 = 14

    3 取反运算:~

      操作符~将每位二进制位取反,1变0,0变1。

    比如 ~6,6的二进制位为0110,~6 = ~0110 = 1001 = 9

    4 异或:^

      操作符^将2个数的每个二进制位异或,2个数对应的位相同,运算结果为0,否则运算结果为1。

    比如 6^10,6的二进制为0110,9的二进制为1010, 0110^1010 = 1100 = 12

    5 右移运算符:>>  右移运算分二种:逻辑右移和算术右移

      ①逻辑右移

    逻辑右移在移动过程中,左边位用0填充。比如1000 0011右移3位,变成0001 0000

      ②算术右移

    算术右移在移动过程中,左边位用符号位填充。比如1000 0011右移3位,变成1111 0000

    6 左移运算符:<<

      左移过程中,右边一律用0填充。0000 1100左移2位为0011 0000

    在实际的编程过程中,往往会用一个整数的不同位表示不同的数据信息。在访问该整数时,就需要通过位运算来获得或者改变整数的某几位数值。比如在Windows中创建文件时使用的Create数据结构: 
    struct 
    {
         PIO_SECURITY_CONTEXT SecurityContext; 
        ULONG Options; 
        USHORT POINTER_ALIGNMENT FileAttributes; 
        USHORT ShareAccess;
        ULONG POINTER_ALIGNMENT EaLength;
        PVOID EaBuffer; 
        LARGE_INTEGER AllocationSize;
     } Create; 
    通常会引用其中的Options如下: 
    Data->Iopb->Parameters.Create.Options 
    ULONG Options是一个Windows文件创建过程中的无符号长整数,指示在创建和打开文件时的不同选项。其中高8位指示了CreateDisposition参数(如FILE_OPEN,FILE_CREATE),低24位指示了CreateOptions参数(如FILE_DELETE_ON_CLOSE)。 为了得到CreateDisposition的值,采取下面的位操作:
     (Data->Iopb->Parameters.Create.Options >> 24) & 0x000000ff; 
    将该整数右移24位,再与0xff做与操作,即可获得CreateDisposition的值。

    二 位运算应用

    1.任何一个数和0异或是它的本身,和自身异或为0:


    a^0=a 
    a^a=0 
    利用上述性质,可以用来计算2个数的交换。
    大家应该知道,在计算机里,两个数互相交换,需要定义一个中间的变量来参与交换。如: 
    int tmp; 
    int a=10; 
    int b=20; 
    tmp=a; 
    a=b; 
    b=tmp; 
    上述代码计算之后,a和b的值完成交换,a的值为20,b的值为10。 
    如果用异或运算来交换2个数,可以如下方法: 
    int a=10; 
    int b=20; 
    a=a^b; 
    b=a^b; 
    a=a^b; 
    上述运行之后,a和b依然完成了值的交换,但由于是异或位运算,所以效率比上面的代码要高。 
    证明:
    a=10^20
    b=a^b=(10^20)^20=10^20^20=10^0=10
    a=a^b=10^20^10=10^10^20=0^20=20
    把上述代码,可以封装为一个交换2个数的函数如下: 
    void swap(int *a, int *b) 

        *a = *a ^ *b; 
        *b = *a ^ *b; 
        *a = *a ^ *b;
     }
    或者用宏来定义:
    #define SWAP(a,b)
    do {
         a = a^b;
         b = a^b;
         a = a^b;
    } while(0)
    但按照下面的方法来写一个函数,试着将两个数进行交换,是错误的(想想为什么?)
    void swap(int a, int b) 

        a = a ^ b; 
        b = a ^ b; 
        a = a ^ b;
     }

    2.将整数的第n位置位或清零:


    #define BITN (1《n) 
    置位:a |= BITN; 
    清零:a &= ~BITN

    3.清除整数a最右边的1。


    方法:a & (a – 1)//该运算将会清除掉整数a二进制中最右边的1。 
    问题:如何判断判断整数x的二进制中含有多少个1? 
    分析:此题是微软公司的一道笔试题。下面用&运算来解决此题。 代码如下: 
    int func(int x ) 
    {
        int countx = 0; 
        while ( x ) 
        { 
            countx++; 
            x = x&(x-1); 
        } 
        return countx; 
    }

    4.用异或运算设计一个只有一个指针域的双向链表:

    提示: 
    要实现该设计要求,需要记住链表的头结点和尾结点,并在链表结点的的next域存放前一个结点和后一个结点的异或值。即: 
    p->next=pl^pr;//头结点的左边结点为NULL,尾结点的右边结点为NULL。 
    在遍历的时候,从头结点往右遍历的方法: 
    pl=NULL;
    p=Head; 
    while(p!=Tail) 

        pr=pl^(p->next); 
        pl=p; 
        p=pr;
     } 
    从尾结点往左遍历的方法: 
    pr=NULL; 
    p=Tail; 
    while(p!=Tail)

        pl=pr^(p->next); 
        pr=p; 
        p=pl; 


    5.计算下面表达式的值


    (char)(127<<1)+1
    (char)(-1>>1)+1
    1<<2+3

    解答:
    (char)(127<<1)+1=(01111111<<1)+1=11111110+1=11111111=-1
    (char)(-1>>1)+1=(11111111>>1)+1=11111111+1=0
    1<<2+3=1<<(2+3)=1<<5=2^5=32(注意《和+的优先级)

      

      

  • 相关阅读:
    BZOJ 3744 Gty的妹子序列
    BZOJ 3872 Ant colony
    BZOJ 1087 互不侵犯
    BZOJ 1070 修车
    BZOJ 2654 tree
    BZOJ 3243 向量内积
    1003 NOIP 模拟赛Day2 城市建设
    CF865D Buy Low Sell High
    CF444A DZY Loves Physics
    Luogu 4310 绝世好题
  • 原文地址:https://www.cnblogs.com/fengxing999/p/10930042.html
Copyright © 2011-2022 走看看