位运算☞二进制神秘面纱

二进制:

       二进制是计算技术中广泛采用的一种数制二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”,由18世纪德国数理哲学大师莱布尼兹发现。当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的。计算机中的二进制则是一个非常微小的开关,用“开”来表示1,“关”来表示0。20世纪被称作第三次科技革命的重要标志之一的计算机的发明与应用,因为数字计算机只能识别处理由‘0’.‘1’符号串组成的代码。其运算模式正是二进制。19世纪爱尔兰逻辑学家乔治布尔对逻辑命题的思考过程转化为对符号"0''.''1''的某种代数演算,二进制是逢2进位的进位制。0、1是基本算符。因为它只使用0、1两个数字符号,非常简单方便,易于用电子方式实现。

位运算:

       程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。比如,and运算本来是一个逻辑运算符,但整数与整数之间也可以进行and运算。举个例子,6的二进制是110,11的二进制是1011,那么6 and 11的结果就是2,它是二进制对应位进行逻辑运算的结果(0表示False,1表示True,空位都当0处理)。

位运算基础:
& 
按位与
如果两个相应的二进制位都为1,则该位的结果值为1,否则为0

按位或
两个相应的二进制位中只要有一个为1,该位的结果值为1

按位异或
若参加运算的两个二进制位值相同则为0,否则为1

void swap(long int &a,long int &b)
{
    a = a^b;          
    b = a^b;        
    a = a^b;        
}                 
void swap(long int &a,long int &b)
{
     a = a+b;
     b = a-b;
     a = a-b;
}


取反
~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1
<< 
左移
用来将一个数的各二进制位全部左移N位,右补0
>> 
右移
将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数, 高位补0

使用技巧_

技巧一:用于消去x的最后一位的1

x & (x-1) 

x = 1100          //二进制1100,12
x-1 = 1011        //减法运算,减1,二进制1011,11
x & (x-1) = 1000  //x&(x-1)运算,去掉二进制中最后一个1,二进制1000,8

 

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

  • 思路解析:N如果是2的幂次,则N满足两个条件。 
  • (1) N>0 
  • (2) N的二进制表示中只有一个1 
  • 一位N的二进制表示中只有一个1,所以使用N&(N-1)将唯一的一个1消去。 
  • 如果N是2的幂次,那么N&(N-1)得到结果为0,即可判断。

1.2.计算在一个 32 位的整数的二进制表示中有多少个 1.

  • 思路解析:
  • 由 x & (x-1) 消去x最后一位知。循环使用x & (x-1)消去最后一位1,计算总共消去了多少次即可。

1.3.将整数A转换为B,需要改变多少个bit位

  • 思路解析 :
  • 思考将整数A转换为B,如果A和B在第i(0<=i<32)个位上相等,则不需要改变这个bit位,如果在第i位上不相等,则需要改变这个bit位。所以问题转化为了A和B有多少个bit位不相同。联想到位运算有一个异或操作,相同为0,相异为1,所以问题转变成了计算A异或B之后这个数中1的个数。

技巧二 :使用二进制进行子集枚举

1.1 给定一个含不同整数的集合,返回其所有的子集
样例:如果 S = [1,2,3],有如下的解: 
[ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2] ]

思路:使用一个正整数二进制表示的第i位是1还是0,代表集合的第i个数取或者不取。所以从0到2^n-1总共2^n个整数,正好对应集合的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

1.1 应用一 数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的。
问题
Given [1,2,2,1,3,4,3], return 4

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

int one_exsit(int *arr ,int len)
{
    int ans = 0;
    for(int i=0;i<len;i++){
        ans^=arr[i];
    }
   return ans;
}

补充:

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

以“与”运算为例说明如下:我们知道在C语言中long型占4个字节,int型占2个字节,如果一个long型数据与一个int型数据进行“与”运算,右端对齐后,左边不足的位依下面三种情况补足,

(1)如果整型数据为正数,左边补16个0。

(2)如果整型数据为负数,左边补16个1。

(3)如果整形数据为无符号数,左边也补16个0。

如:long a=123;int b=1;计算a& b。

如:long a=123;int b=-1;计算a& b。

如:long a=123;unsigned intb=1;计算a & b。


 

猜你喜欢

转载自blog.csdn.net/ox0080/article/details/83927562