ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

位运算

2020-05-16 10:54:35  阅读:241  来源: 互联网

标签:Hash 运算 二进制 lowbit 补码 取反


其实位运算很好理解,又比较好用,状态分明,易于想象,反正不是1就是0

还算轻松的开头


 

 基础算术位运算

与  and  &:两者都为1则为1,其他情况都为0

或    or    |:两者都为0则为0,其他情况都为1

非  not   ~:对于一个二进制数,每位取反,0变为1,1变为0

亦或 xor ^:两者相同则为0,不同则为1

 

补码

unsigned int:32位无符号整数  可以直接把32位编码看成32位二进制数

int:32位有符号整数  最高位表示正负,0为正,1为负

对于int型数,正数补码为它本身,负数补码为除符号位外所有位取反后再+1

所以对于一个int数x,全部位取反后得到的数为-1-x

已知补码求原码:

如果补码的符号位为0,表示是一个正数,其原码就是补码。

如果补码的符号位为1,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。

 

反码

正数的原码、补码、反码都相同,都等于它本身

负数的反码是,符号位不变,其余各位求反

负数反码末位加上1就是补码


注意点:

对一个数取反是对这个数的补码取反

电脑保存的二进制数都是它的补码,在补码下每个数都有唯一表示方式

两个数值做加减法运算,实质上是它们的补码做最高位不进位的二进制加减法运算

 

表示

在写程序的时候,常用十六进制来表示一个数,共8个字符,每个字符代表二进制中4个位

用“0x”开头,声明进制

后面跟上代表四位二进制数的字符(0~9,A~F)

例如:3  ->  000……0011  ->  0x00000003(0011对应的十六进制为3)

虽然int型最大正整数应该是0x7FFFFFFF,但一般用0x3F3F3F3F来表示最大值

 

移位运算

左移

在二进制表示下所有位的数同时向左移动,低位0填充,高位如果超过范围就舍弃

易得:1<<n=2n  n<<1=2*n

右移

在二进制表示下所有位的数同时向右移动,低位超过范围舍弃,高位以符号位填充

n>>1=n/2

等于除以2向下取整,但整数/2在c++中实现为向零取整

所以,正数右移1位和除以2相同,但负数就不一样。例:(-3)>>1==-2,(-3)/2=-1

 

二进制状态压缩

用二进制数表示状态,典型运用状态压缩dp

取出整数n在二进制表示下的第k位     (n>>k)&1

取出整数n在二进制表示下的第0~k-1位(即后k位)  n&((1<<k)-1)

把整数n在二进制表示下的第k位取反    n^(1<<k)

把整数n在二进制表示下的第k位赋值为1    n|(1<<k)

把整数n在二进制表示下的第k位赋值为0    n&(~(1<<k))

 

lowbit运算

lowbit(x)指非负整数x在二进制表示下 最低位的1及后面所有的0构成的数

lowbit(x)=x&(~x+1)=x&(-x)

推导过程:

设x的最低位1在第k位,则第0~k-1位都为0

把x取反,则第k位为0,0~k-1位都为1,第k+1~最高位与之前相反

再+1后,由于进位,第0~k-1位再次变为0,第k位变为1

而+1操作对第k+1~最高位无影响,所以恰好与原数相比相反

这个时候把操作后的数与x进行 和运算,则从第k+1~最高位都为0,得到答案

即lowbit(x)=x&(~x+1)

又由补码表示下可得~x+1=-n,所以lowbit(x)=x&(-x)

 

找出整数二进制下所有是1的位

用lowbit运算+Hash

求lowbit(x)可以求出最低位为1的位置,再把x赋值为x-lowbit(x),可以求出下一个为1的位,反复直到x=0

 

求出的lowbit(x)为一个最高位为1,其余位都为0的数,这个数一定是2的n次方,而这个n就是它的最高位数,即原x中的1在第n位中(注:k位二进制数,这里最低位表示为第0位,最高位表示为第k-1位)

要确定n,用Hash存储,可以实现O(1)的询问

预处理Hash数组,把2n存储为n,即Hash( 2n )=n

举个例子:要求十进制数x=10的二进制下所有是1的位

x=10=(1010)2    ->   lowbit(x)=(10)2=2    ->    Hash( lowbit(x) )=Hash( 2 )=1   ->   x=x-lowbit(x) 即x=8=(1000)2  ->   lowbit(x)=lowbit(8)=(1000)2=8   ->  Hash( lowbit(x) )=Hash( 8 )=3    ->  x=x-lowbit(x)=0  ->停止

用Hash求出的标红的两个数1、3即为所求

程序实现

for(int i=0;i<=20;i++)    Hash[1<<i]=i;
while(x)
{
    printf("%d ",Hash[x&(-x)]);
    x-=x&(-x);
}

 


大致就是这些,位运算一般都是题目中的一部分辅助工具,不太会单独出现。

 

参考  李煜东的《算法竞赛进阶指南》

 

标签:Hash,运算,二进制,lowbit,补码,取反
来源: https://www.cnblogs.com/mgtnb/p/12891205.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有