目录

  • 判断奇偶数
  • 交换两个数
  • 子集枚举
  • 求数的n次方
  • 判断是不是2的整数幂
  • 在其余数都出现偶数次的数组中找出出现奇数次的数
  • 找出那两个出现了奇数次的数
  • 不使用算数运算符进行加法运算
  • 不使用算数运算符进行减法运算
  • 不使用算数运算符进行乘法运算
  • 不使用算数运算符进行除法运算
  • 最后

以下是关于位运算的一点常用方法总结以及仅使用位运算的加减乘除实现。

判断奇偶数

因为二进制除了最后一位上是1时代表是十进制的1,其余位上是1时都是代表着2的倍数,所以如果一个数最后一位是1就可以判断为奇数;
反之可以判断为偶数;

int jioushuJudge(int n){if(n & 1 == 1){cout << "该数是奇数";} else {cout << "该数是偶数";}
}

交换两个数

首先我们先明确一下异或的作用是如果两数相同就等于0,如果不同则为1.所以我们可以得到两个性质
1.一个数异或0等于本身;
2.一个数异或本身等于0;
而异或^是可以使用交换律的.
所以我们把新的x带入到第二行中的x就可以看到是y = (x ^ y) ^ y,经过交换律变化可以为y = x ^ (y ^ y),即为y = x ^ 0 = x;到这就已经把x的值赋给了y
同样的,把第一行的x带入到第三行中可以交换变为x = (x ^ x) ^ y = 0 ^ y = y,就完成了把y赋值给x的操作

int swap(int x, int y){x = x ^ y;y = x ^ y;x = x ^ y;
}

子集枚举

对若干个名字进行排列组合.
我们可以把名字取不取分为0或者1,然后有几个名字就是几位二进制数.每一位数都对应着一个名字.最后只需要判断对应位上是0还是1就可以知道取不取该名字.

string names[4] = {"Alex","Laurie","doinb","xiaohu"
};
void work(int n, int x) {for (int i = 0; i < n; i++) {//其中的(1 << i)是使一位上是1,然后经过与运算就可以判断x该位上是否是1if (x & (1 << i))cout << names[i] << ' ';}cout << endl;
}int main() {int n = 4;for (int i = 0; i < (1 << n); i++) {//4位数一共有2的4次方的组合数,(1 << 4)代表的是往左移4位,等于2的4次work(n, i);}return 0;
}

求数的n次方

此处求的是2的n次方.想法是把n转换成二进制数,然后把有1的位数单独拿出来进行次方运算,例如:2的11(1011)次方=(2 ^ 8) * (2 ^ 2) * (2 ^ 1)

int cifang(int n) {int res = 1;int x = 2;while(n != 0){if(n & 1 ){res *= x;}x *= x;//相当于次方数*2n = n >> 1;}cout << res;
}

判断是不是2的整数幂

因为二进制的从最右边开始是2的0次幂开始往右增加,所以只需要把原数和原数-1进行与&运算是不是为0可以判断出是否是2的整数幂了。因为2的整数幂只会存在一个1,所以-1把那个1变为0,并且低位全部为1,相与为0说明是2的整数幂。

bool judge(int n){if(n & (n - 1)) return false;return true;
}

在其余数都出现偶数次的数组中找出出现奇数次的数

题目是这样的:有n个数,只有一个数没有重复过,其他数都出现了两次,那个怎么找出那个数?
这里也需要用到异或运算符的一个性质,两个相同的数异或结果等于0,所以我们直接把所有数都异或一遍,由于交换律,重复的数都变为0了,所以剩下的单独的数和0异或还是他本身,这就求出来了。

int find(int n){int a[n];int res = 0;for(int i = 0; i < n; i++){cin >> a[i];res ^= a[i];}return res;
}

找出那两个出现了奇数次的数

这道题比上一题稍微难一点,但是思路都是一样的。
我们先把所有数都异或得到一个数,这个数是我们要求的两个数的异或结果。
这样还不可以分出是哪两个数。由于这是异或的结果,所以里面的1肯定是两个数不同才产生的,而且这个1必定是一方所有的,因为只有0和1才能异或为0.这样我们只需要找出那个1的位置然后把所有数中的那个1位置是1的数全部异或一遍.
这样的结果就是其中一个数了(这次是因为第二个数没有参加异或,而参加了的都是偶数次,除了目标数)。
最后再把找出的数和第一次异或的数异或以下就可以得到第二个数了。

int find(int n){int a[n];int res = 0;int ress = 0;for(int i = 0; i < n; i++){cin >> a[i];res ^= a[i];}int locate = res & -res;//一个数前面加一个-就是把这个数取反然后再加一,这样就可以得到最右边的那个1的位置for(int i = 0; i < n; i++){if(a[i] & locate)ress ^= a[i];}int res2 = res ^ ress;cout << ress << ' ' << res2;
}

不使用算数运算符进行加法运算

众所周知,在加法中,对小学生来说有一个“难”问题,那就是进位。而在位运算中使用加法也要考虑这个问题。
首先我们把两个数进行异或运算,这样可以考虑不进位的情况,得到的结果是把两个对应的1消掉但是还没进位的情况,记为a。
然后我们通过两数相与得到两个1消掉的位置(两数相与就可以把一样的1保留下来),再通过<<1来得到需要加1的地方,记为b。
然后判断b是否为空,如果b不为空,说明存在进位的情况,这时我们就把a和b当作新的两个数重新进行以上操作,把a中需要加的对应位上的1加上。
这样直到b为空为止,说明进位结束,此时a就是两数相加的结果。

int add(int a, int b){int sum = a;while(b){sum = a ^ b;//不进位情况之和b = (a & b) << 1;//进位所产生的需加上的数a = sum;}return sum;
}

不使用算数运算符进行减法运算

加法都写出了,减法就不在话下了。把要减去的数改为取反后的原减数加1;简单的调用加法函数就可以了。

int Minus(int a, int b){int c = add(~b, 1);return add(a, c);
}

不使用算数运算符进行乘法运算

其实二进制的乘法和十进制的差不多,只需要把进位改为2就可以了。我们先来手动写一个乘法来找找规律。

可以发现相当于每次都是加上a乘2的所在位的位数-1次,也就是加上把a向左移动几位的数。
既然有这个规律,我们在每次如果b不为0并且b最后一位为1时,sum加上一个a,然后把a往左移一位,b右移一位(看下一个数)。当然别忘了,b不为零但是最后一位为0时也不要忘了把a左移,b右移,只不过这种情况不往sum里加而已。
还有一个问题,就是符号的问题,我们只能先把两个数都变成绝对值进行计算,最后再根据符号进行添加符号。

int Mul(int a, int b){int a1,b1;if(a < 0) a1 = add(~a, 1);//取绝对值else a1 = a;if(b < 0) b1 = add(~b, 1);//取绝对值else b1 = b;int sum = 0;while(b1){if(b1 & 1){sum = add(sum, a1);}a1 = a1 << 1;b1 = b1 >> 1;}if((a ^ b) < 0)//如果有一个是负数的话结果也会是负数,所以取反加一return add(~sum, 1);else return sum;
}

不使用算数运算符进行除法运算

除法和乘法的性质差不多,但是有点不同。除法的本质是减法,所以每次都减去除数,然后次数加一,直到被除数小于除数为止。
但是这种方法效率太低,所以可以使用二分的思想进行优化。
举个例子,比如2的9次方可以是2+2+2+2+2+2+2+2+2,也可以是2的8次方+2,也可以是2的4次方+2的4次方+2(差不多这个意思,能看得懂吗hh),每次以2的幂来进行判断会快很多。
因为int型是有32位的,所以我们要从最大的31位开始判断,因为第32位是符号位。
有个问题需要注意,为了避免数据溢出,所以不使用除数乘2次幂来进行判断,改用被除数输除以2次幂来判断。
i不断变小,知道被除数右移i位后大于除数为止,这说明这是这个除数与2次幂相乘最接近被除数的一个数,然后被除数减去该数,以及次数加上这个2次幂,这样和一个一个减一下子就快了不少。
当然和乘法一样,符号也要考虑。

int devide(int a, int b){   int a1,b1;if(a < 0) a1 = add(~a, 1);//取绝对值else a1 = a;if(b < 0) b1 = add(~b, 1);//取绝对值else b1 = b;int res = 0;for(int i = 31; i >= 0; i = minuss(i, 1)){//为了避免使用--,所以调用减的函数if((a1 >> i) >= b1)//这里是为了避免溢出,所以用a1右移而不是b1左移{res = add(res, (1 << i));a1 = minuss(a, (b1 << i));}}if((a ^ b) < 0)//如果是负数,就取反再加一res = add(~res, 1);return res;
}

最后

以上是关于位运算的一些使用方法(以后有新的会有补充)以及加减乘除的实现,新手上路,有错请指正;


撒花

【Cpp】关于位运算的常用实用方法个人总结以及加减乘除的实现。「加减乘除」相关推荐

  1. c语言或者cpp中位运算的技巧

    简述 在知乎上看到一个题目,解答很有意思,用的是位运算. 这让我觉得位运算有更多的算法可能,但是却还没被我用过. 这种东西都是第一次看,觉得挺牛的,第二次,第三次看的时候就觉得没什么了.So,大佬们轻 ...

  2. 位运算简介及实用技巧(一):基础篇

    去年年底写的关于位运算的日志是这个Blog里少数大受欢迎的文章之一,很多人都希望我能不断完善那篇文章.后来我看到了不少其它的资料,学习到了更多关于位运算的知识,有了重新整理位运算技巧的想法.从今天起我 ...

  3. 位运算简介及实用技巧(二):进阶篇(1)

    =====   真正强的东西来了!   ===== 二进制中的1有奇数个还是偶数个     我 们可以用下面的代码来计算一个32位整数的二进制中1的个数的奇偶性,当输入数据的二进制表示里有偶数个数字1 ...

  4. 位运算简介及实用技巧(四):实战篇 [Matrix67]

    Problem : 费解的开关 题目来源     06年NOIp模拟赛(一) by Matrix67 第四题 问题描述     你玩过"拉灯"游戏吗?25盏灯排成一个5x5的方形. ...

  5. typescript 方法后面加感叹号_typescript专题(四) 「泛型」

    欢迎来到我专题文章[typescript],更多干货内容持续分享中,敬请关注! 上一章节我们讲到了在typescript中的接口类型的基本使用 本章目标: 什么是泛型 类型类 泛型接口 什么是泛型 我 ...

  6. 为什么jvm要分为堆、方法区等?原理是什么?_「JVM」知识点详解一:JVM运行原理详解...

    前言 JVM 一直都是面试的必考点,大家都知道,但是要把它搞清楚又好像不是特别容易.JVM 的知识点太散,不系统,今天带大家详细的了解一下jvm的运行原理. 正文 1 什么是JVM? JVM是Java ...

  7. 大AI巧用「砌砖」方法:LLM可通过将任务「外包」给专业领域的AI模型来提高其性能...

    来源:ScienceAI 本文约1800字,建议阅读5分钟 新的研究表明,让 LLM 将工作外包给规模较小的专业 AI 可以显著扩大其范围. 大型语言模型(LLM)功能的快速改进使它们能够处理范围广泛 ...

  8. 便利店里的常用日语:“找”的日语不都是「探す」

    ZH    我要您1001元. JA    1001円のお買い上げです. ZH(店员问客户):你有零钱吗? JA     ❌お釣りがありませんか.                  お釣り       ...

  9. LeetCode #1349. 参加考试的最大学生数 - 学到了:压缩状态动态规划、位运算、reduce()、str().count()

    赛题见:https://leetcode-cn.com/problems/maximum-students-taking-exam/ 我的解法是用递归实现广度优先搜索,结果是对的,但是太慢,超时了.这 ...

最新文章

  1. hdu 1003 Max Sum 解题报告
  2. webpack 4.0 小记
  3. OPenCV学习笔记八-图像的滤波
  4. J2EE搭建Dynamic web SpringMVC工程404错误分析(三)
  5. 阻碍物联网腾飞几大难题盘点 看能想出什么对策
  6. Tomcat解决HTTP GET中文乱码
  7. HTML期末作业-牛排美食餐厅网站
  8. 基类显式继承接口,类继承基类时又继承同一接口,引发接口方法混乱(显式继承接口的弊端)...
  9. mysql 数据库缓冲池_MySQL5.6新特性快速预热Buffer_Pool缓冲池
  10. Why does getView return wrong convertView objects on BaseAdapter?
  11. Oracle 中 varchar2 和 mysql 中 varchar到底能存多少个汉字?
  12. CVPR 2021 UniT: Multimodal Multitask Learning with a Unifified Transformer
  13. CSDN的MD编辑器【写作技巧】
  14. 2021年高处安装、维护、拆除考试及高处安装、维护、拆除考试技巧
  15. vpython_vpython初探
  16. 轮流取石子游戏c语言答案,取石子游戏
  17. 无法显示页面,因为发生内部服务器错误。
  18. 大文件上传控件webupload插件
  19. 杭电考研计算机专业课_2019杭电计算机考研初试科目、参考书目、报录比汇总...
  20. 为什么特斯拉Q2业绩能超预期?

热门文章

  1. 可组合的临时堆栈Polymath:以太坊中的区块链
  2. svn 只更新某个目录
  3. 安防视频监控系统视频上云解决方案EasyCVR语音转发功能音频数据打包发送流程介绍
  4. python七夕快乐_用python度过一个温馨的单身七夕节-安利篇
  5. Atmel Studio 6使用
  6. 红鲱鱼:视频创新的制高点
  7. Template、ItemsPanel、ItemContainerStyle、ItemTemplate(包括ListBox的Item子项是横向排列)...
  8. 中国金融集成电路(IC)卡规范(PBOC3.0)简单介绍
  9. tf卡和sd卡引脚定义和性能指标
  10. 项目开发-疯狂连连看游戏开发