位运算计算与位运算应用

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

一 位运算计算数据结构

1 与运算:&函数

  操做符&将2个数的二进制位进行与操做,2个数对应的位都为1,运算结果为1;不然运算结果为0。设计

好比 6&8,6的二进制为:0110   8的二进制为:1000。因此6&8 = 0000 = 0指针

2 或运算:|blog

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

好比 6&8,6的二进制为:0110   8的二进制为:1000。因此6&8 = 1110 = 14io

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)+11<<2+3解答:(char)(127<<1)+1=(01111111<<1)+1=11111110+1=11111111=-1(char)(-1>>1)+1=(11111111>>1)+1=11111111+1=01<<2+3=1<<(2+3)=1<<5=2^5=32(注意《和+的优先级)

相关文章
相关标签/搜索