位运算的一些奇技淫巧


位运算这种计算方式已经淡出我的编码习惯很久了,最近突然看见一篇推文在讲一些位运算在特殊场景下的奇妙作用,这显然勾起了阿光对于位运算的一泡浓厚的兴趣,于是我就搜集了一些位运算常用的技巧在这里和大家分享一下。

其实像这种技巧题目的话知道就行了,能做到遇到类似的情况会用就行,想要真的自己去发现这些东西还是有点难度的,就交给大佬们去做吧!

位运算简介

常见的位运算也就是以下6种:

| 运算:即或运算,全0则0

& 运算:即与运算,全1则1

^ 运算:即异或运算,相同为0,不同为1

~ 运算:即非运算,0为1,1为0

(<<) 运算:左移运算,高位丢弃,低位补0

(>>) 运算:右移运算。(无符号)低位丢弃,高位补0;(有符号)低位丢弃,高位补符号

常用的就是这6种,一般解题中也完全够用了!

技巧介绍

1.位操作实现加减乘除运算

加法运算

这里先从加法运算说起:

我们假设

a: 001010101
b: 000101111

在无进位相加下,a^b 就可以达到相加的目的;而在只考虑进位的位的情况下,就是只考虑进位产生的值的时候,我们可以用(a&b)<< 1,那么我们结合上面两种情况是不是可以这么想:我们将a^b的值和(a&b)<<1的值轮番进行求 ^ 和 &<<1 运算,直到最后&<<1的值算为全0,这就意味着所有的进位都已经被 ^ 进结果了,那么最终的结果就是求和的值了

我们可以看见,当最后 &<<1 的结果为0时,说明所有的进位都已经被加到结果中去了,那么该结果也就是最终的计算结果了。

这里我们用代码把它表示出来:

int add(int a,int b)
{int sum = a;while(b != 0){sum = a ^ b;b = (a & b) << 1;a = sum;}
}

减法运算

那么减法运算就很好理解了,我们可以认为a-b = a+(-b),这里就是要求得b的相反数,那么根据规则,一个数的相反数(补码)就等于反码加1,那么我们是不是可以这么写:

int minus(int a,int b)
{return add(a , add( ~b , 1));
}

乘法运算

假设我们要计算 a * b,那么我们就可以写成a * 2^0 * b0 + a * 2^1 * b1 + …+ a * 2^31 * b31,其中bi为 0 或者为 1 代表整数 b 的二进制数表达中第 i 位的值。

这里我们同样举一个例子:

a = 22 = 000010110
b = 13 = 000001101
res = 0= 000000000

也不知道是哪一位鬼才总结出这种神奇的算法,说实话,有这个计算的功夫,我用正常的计算方法都交卷了。除了应对一些题目外,大家了解一下就好了。

下面用代码描述一下上面的过程:

int multi(int &a,int &b)
{int res = 0;while (b != 0){if((b & 1) != 0){res = add(res,a);}a<< = 1;b>> = 1;}return res;
}

除法运算

这里就不过多赘述了,由于使用的很少加上思路和乘法是一样的,大家有兴趣的可以自己下来推一下。(其实是阿光不想写了)

交换两个整数值

如果有人说让你交换两个整数的值但不能额外申请第三个变量,你准备使用什么方法呢?

那么你应该想到这种方法:

int swap(int &a,int &b)
{a = a ^ b;b = a ^ b;a = a ^ b;
}

这里解释一下:
首先,a = a ^ b; 那么 b = a ^ b = (a ^ b) ^ b = a,那么这里就把 a 的值成功的给了b; 第三步就是将前两步的结果带入计算: a = (a ^ b) ^ a = b; 交换值的目的就达到了。是不是很奇妙呢?

判断奇偶数

我觉得这个方法正是让人眼前一亮,核心思想其实就是根据数的最后一位是0还是1来做判断,那么就有:

if((a & 1) == 0){//是个偶数
}
else//是个奇数

高低位交换

这个还是比较常用的,在很多客制化的协议里面,常常涉及到高低位交换的操作。假设有一个16位无符号,将其高8位和低8位进行交换:

举个例子: 00111010 01010011…
那么高低8位进行交换就得到: 01010011 00111010 这就是完全不相同的两个数了。

从上面的操作我们可以看出,将无符号数 a >> 8 就可以将高8位转移到低8位,高位补0; 同时将a << 8 就可以将低8位转移到高8位,低8位补0,然后将 a >> 8 和 a<< 8 尽行或操作就可以求得交换后的结果。

unsigned short a = 34520;
a = (a >> 8) | (a << 8)

统计二进制中1的个数

这里巧妙的用到了一个 a &= (a-1),说一下原理:

a与a-1进行运算,那么每次都可以消去一个1,那么我们搞一个计数器,当把a所有的1都消去之后,返回计数器的值就可以了,非常的方便

count = 0;
while(a)
{a = a & (a-1);count++;
}
return count;

在出现偶数次的数组中找出奇数次的数

这里我们直接看一个力扣上的题目:

给定一个数组arr,其中只有一个数出现了奇数次,其他的数都是偶数次,将这个数打印出来。

其实想一下这个题目可以有很多方法都能做出来,但是题目给出的要求是时间复杂度O(N),常规方法遍历一遍能找出来吗?我是没有想到什么好方法,这里提供一种位运算的思路:

整数n与0异或的结果是 n,整数n与整数n异或的结果是0. 我们申请一个整形变量 A0赋值为0 ,将A0与arr中的每一个数求异或,那么最后留下来的那个数就是只出现过一次的数,可以揣摩一下。

int getjishunum(int *arr)
{int A0 = 0;for(int i = 0;i < arr.length; i++)A0 ^= arr[i];return A0;
}

大小写转换

除了上面的妙用以外,利用或运算|和空格将英文字符转化为小写

(‘a’ | ’ ') = ‘a’
(‘A’ | ’ ') = ‘a’

利用与运算 & 和下划线将英文字符转化为大写

( ‘b’ & ’ _ ') = ‘B’
( ‘B’ & ’ _ ') = ‘B’

利用异或操作 ^ 和空格进行英文字符大小写互换

(‘d’ ^ ’ ') = ‘D’
(‘D’ ^ ’ ') = ‘d’

以上便是关于位运算的一些技巧,其实只有用的多了才能掌握其中的一些规律,总结出属于自己的一套使用方法。纸上得来终觉浅啊XDM,下来有空了可以画一画,对于日常的项目开发还是很有用的!

位运算的一些奇技淫巧相关推荐

  1. 位运算的那些奇技淫巧 | 掌(装)握(逼)必备,妙解两道算法题

    这里写目录标题 一.常(装)见(逼)的位操作 先看几个有意思的位操作: 1.判断奇数偶数 2.交换两个数字 3.找出没有重复的数字 4.m的n次方 5.判断一个数是不是二的指数 6.找出不大于N的最大 ...

  2. 巧用位运算实现大小写转换

    今天看王爽老师的<汇编语言>时,很有收获,不论是技术还是思考方式. 任务是将字符串进行大小写转换,但是还暂时不会用分支判断语句(而且这样的效率也不是最高的,有点类似于高级语言了). &qu ...

  3. 位运算——强大得令人害怕

    前言 众所周知,位运算是我们学计算机必学的东西,前人用二进制.位运算给我们了一个操作简单的计算机,但我们却很少接触位运算了.今天介绍一些位运算在算法中的运用. 位运算基础 & 按位与 如果两个 ...

  4. python中不同进制的整数之间可以直接运算_Python 进制转换、位运算

    一.进制转换 编程用十进制,十进制转换为二进制.八进制.十六进制 In [135]: bin(23) Out[135]: '0b10111' In [136]: oct(23) Out[136]: ' ...

  5. python isodd()判断奇偶_位运算(1的个数;2.判断奇偶)

    1. 1的个数 int NumberOf1(intn){int count = 0;while(n) {++count; n=(n-1)&n; } } 同样一个问题,位运算可以提高程序的运行效 ...

  6. python 整数逆位运算_python训练营:注释、运算符、数据类型与位运算

    天学习的内容整理成脑图如下,其中带☆的是需要重点掌握的模糊知识点,需要加强训练和记忆. 二.具体学习内容 2.1 注释 2.1.1 多行注释 2.1.2 长字符串注释 2.2 运算符 2.2.1 算术 ...

  7. 洛谷P1896 [SCOI2005]互不侵犯 状压dp+位运算

    题目链接:https://www.luogu.org/problem/P1896 题意:n*n的格子填数,每个数填放位置的周围(8个)不能有其他的数 n<=9 ,矩形状压 f[i][j][s], ...

  8. mysql 使用位运算

    如果你不知道什么是位运算的话, 那么请你先去看看基础的C语言教程吧. 与运算 a & b  , 或运算 a | b ,  异或运算 a ^ b , 或者 你也可以将 与运算理解为 + 法  例 ...

  9. 位运算+取某一位+java_Java位运算小节

    2019新春支付宝红包技术大揭秘在线峰会将于03-07日开始,点击这里报名届时即可参与大牛互动. 位运算表达式由操作数和位运算符组成,实现对整数类型的二进制数进行位运算.位运算符可以分为逻辑运算符(包 ...

最新文章

  1. veeam.Backup.and.Replication 6 测试之二--backup和replication功能
  2. 【Charles】Breakpoint 断点
  3. mysql55w.x86 64 卸载_Cent6.5 64位yum安装mysql5.5
  4. uuid怎么获取_我们经常说的限流应该怎么做?
  5. 2020年这10大机器学习研究最具影响力:为什么?接下来如何发展?
  6. Prism Training Kit 4.0
  7. Python使用组合、排列和动态规划算法求解0-1背包问题
  8. 三大电商(淘宝、京东、拼多多)开放平台 服务市场 过程中常用文件和注意事项(PRD,MRD)
  9. 如何建立企业员工满意度测评指标体系
  10. 修改mysql的authen_MySQL连接抛出Authentication Failed错误的分析与解决思路
  11. java数据类型 枚举_枚举(enum)属于原始数据类型(primitive typ
  12. 音视频开发之基于某三方音效的Android native层四声道音频输出
  13. FFmpeg一些感想
  14. Ecshop模板开发(二十三):手机版显示商城
  15. 如何彻底卸载云上PDF?一个非常简单的教程
  16. 10.sprd背光流程
  17. macOS上的符号链接Symlink是什么,以及该怎么使用
  18. 伴鱼使用教程!【原创】
  19. 我喜欢出发 - 汪国真
  20. RGB、CMY、HSV、HSL颜色空间

热门文章

  1. 刀疤鸭背单词-先疯盗骨
  2. vue中嵌套页面(iframe)
  3. hive-diea-ETL数据截取split,嵌套SQL查询,ETL-SQL表查询中间件解析
  4. es审计日志_【Elasticsearch7.0】之日志审计功能
  5. 微信可以登录QQ了!
  6. BIGEMAP 如何选择分度带(中央子午线)
  7. 国外交友网站即时通讯支持多语言社交网站源码
  8. 点积(点乘、数量积、内积)和叉积(叉乘、向量积、外积)
  9. Spark源码解读之Shuffle计算引擎剖析
  10. php 序列化 反序列化 __sleep __wakeup