程序员的数学基础课
黄申
LinkedIn 资深数据科学家
83374 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 58 讲
导读 (1讲)
基础思想篇 (18讲)
程序员的数学基础课
15
15
1.0x
00:00/00:00
登录|注册

数学专栏课外加餐(二) | 位操作的三个应用实例

利用异或的特性
存储中间变量
单线剧情和分支剧情
编程实现的不同
使用数学归纳法节约时间
证明结论是否成立
正向思维和逆向思维
避免溢出的优化
BitSet在Elasticsearch中的应用
按位与和按位或操作
二进制表示集合
利用异或特性交换变量值
位运算效率比较
位运算判断奇偶数
寻找重复出现的数字
分治思想和分布式系统
递归编程的特性
循环和递归的适用场景
迭代法和递归的关系
迭代问题的编程实现
数学归纳法
迭代法和递归
误差百分比和绝对误差
中间值的计算
集合操作
交换两个数字
验证奇偶数
思考题
关于迭代法、数学归纳法和递归
二分查找时的两个细节
位操作的应用实例
位操作的三个应用实例分析

该思维导图由 AI 生成,仅供参考

你好,我是黄申。欢迎来到第二次课外加餐时间。

位操作的应用实例

留言里很多同学对位操作比较感兴趣,我这里通过计算机中的位操作的几个应用,来帮你理解位操作。

1. 验证奇偶数

第 2 节里,我提到了,奇偶数其实也是余数的应用。编程中,我们也可以用位运算来判断奇偶数。
仔细观察,你会发现偶数的二进制最后一位总是 0,而奇数的二进制最后一位总是 1,因此对于给定的某个数字,我们可以把它的二进制和数字 1 的二进制进行按位“与”的操作,取得这个数字的二进制最后一位,然后再进行判断。
我这里写了一段代码,比较了使用位运算和模运算的效率,我统计了进行 1 亿次奇偶数判断,使用这两种方法各花了多少毫秒。如果在你的机器上两者花费的时间差不多,你可以尝试增加统计的次数。在我的机器上测试下来,同样次数的奇偶判断,使用位运算的方法耗时明显更低。
public class Lesson1_append1 {
public static void main(String[] args) {
int even_cnt = 0, odd_cnt = 0;
long start = 0, end = 0;
start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
if((i & 1) == 0){
even_cnt ++;
}else{
odd_cnt ++;
}
}
end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(even_cnt + " " + odd_cnt);
even_cnt = 0;
odd_cnt = 0;
start = 0;
end = 0;
start = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
if((i % 2) == 0){
even_cnt ++;
}else{
odd_cnt ++;
}
}
end = System.currentTimeMillis();
System.out.println(end - start);
System.out.println(even_cnt + " " + odd_cnt);
}
}

2. 交换两个数字

你应该知道,要想在计算机中交换两个变量的值,通常都需要一个中间变量,来临时存放被交换的值。不过,利用异或的特性,我们就可以避免这个中间变量。具体的代码如下:
x = (x ^ y);
y = x ^ y;
x = x ^ y;
把第一步代入第二步中,可以得到:
y = (x ^ y) ^ y = x ^ (y ^ y) = x ^ 0 = x
把第一步和第二步的结果代入第三步中,可以得到:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文通过三个实例展示了位操作的技术特点和应用场景。首先,位操作可以高效地判断奇偶数,展示了位操作的高效性。其次,利用异或运算可以实现在计算机中交换两个数字的值,避免了使用中间变量,提高了效率。最后,通过集合的二进制表示和位运算,展示了位操作在集合操作中的应用,以及在Elasticsearch中的实际应用场景。此外,还介绍了二分查找中的两个细节,分别是避免溢出的计算中间值和误差百分比的应用。这些实例充分展示了位操作在计算机编程中的重要性和实用性。文章还介绍了迭代法、数学归纳法和递归的概念及其联系,以及它们在计算机编程中的应用。文章最后提出了一个思考题,引发读者思考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《程序员的数学基础课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(61)

  • 最新
  • 精选
  • Jerry银银
    我的天,昨天才为老师的加餐点过赞,今天又来一篇干货。谢谢老师,看了这两篇加餐,心里的很多疑惑被解除了。买老师的专栏,值了。 —— 思考题: 需要考虑不同的数量级,分两种情况: 1. 内存能容纳这n个数 方法1:暴力查找,两层循环遍历,时间复杂度为O(n^2),空间复杂度为O(1) 方法2:用快排先进行排序,然后遍历一次,比较前一个数和后一个数,若相等,则查找完成,时间复杂度O(nlogn),空间复杂度为O(1) 方法3:利用hash表(或set),进行一次遍历,同时将遍历到的数放入hash表,放入之前判断hash表是否存在,若存在,则找到了重复的数,时间复杂度为O(n),空间复杂度为O(n) 方法4:使用位向量,遍历给到的n个数,对于出现的数,将对应位标记为1,如果已经是1则查找成功,时间复杂度为O(n),空间复杂度为(n),这种方法类似方法3,虽然渐进的空间复杂度和方法3相同,但是其实小很多很多,毕竟只要用1bit就能表示有或无 2. 内存无法容纳给到的n个数 依然可以用上述方法4来解决,其它的方法有的不能用,有的效率不高。

    作者回复: 感谢支持,思考题分析的很透彻,各种情况都考虑到了

    2018-12-26
    2
    48
  • 科哥
    根据异或的两个特点,任何两个相同的数异或的结果都为0,任何数与0异或都为这个数,因此将所有的数依次异或得到的结果就是除了两个重复数的所有数的异或结果,假设为T。而将1到n依次异或的结果为T^重复数。因此,重复数=T^T^重复数。即:所有数异或的结果再异或1到n所有数异或的结果

    作者回复: 很好的思路👍

    2018-12-26
    28
  • 胡鹏
    看到 Brian Wang 的回答, 您说了正解, 我才想明白: 推到应该是: 原始数据: 1,2...m,m,...n (是否有序对此题不重要) 所有数字: 1,2,...m,...n 因为 x^x = 0 令a = 1^2...^m...^n b = 1^2...^m^m...^n 则有: a^b = (1^2...^m...^n)^(1^2...^m...^n)^m = 0^m = m

    作者回复: 是的 👍

    2018-12-30
    3
    27
  • Bryan
    思考题:对于有的全部数字进行异或再和 1-n 这 n 个数字进行异或,最终得出的结果就是 m

    作者回复: 正解

    2018-12-26
    9
  • 指间砂的宿命
    将所有结果异或再和1到n的不重复结果异或,最后剩余的值就是重复值,真的好神奇,这种异或用法

    作者回复: 嗯 异或的妙用

    2018-12-26
    5
  • 蜉蝣
    如果给出的数字不连续,Python中不妨这样使用: ```python from itertools import chain nums_list = [1, 2, 10, 8, 2, 3] nums_set = set(nums_list) start = 0 # 任何数与 0 异或得到自己,所以作为初始值使用 for num in chain(nums_list, nums_set): start = start ^ num print(start) ```

    作者回复: 正确

    2019-01-08
    3
    3
  • 张雷
    请教老师,用异或交换两个变量值感觉不太懂: 第一步代入第二步时,y已经=x了, 再把第二步代入第三步,此时y的值已经是x,怎么还能利用它把原y值传给x呢? 感觉还是要临时变量做过渡啊?

    作者回复: 因为此时新的x值还是x^y,而新y已经是原来的x,两种异或,就是y了

    2018-12-26
    3
  • 夏飞
    假设我们有两个集合{1, 3, 8}和{4, 8}。我们先把这两个集合转为两个 8 位的二进制数,从右往左以 1 到 8 依次来编号。 如果某个数字在集合中,相应的位置 1,否则置 0。那么第一个集合就可以转换为 10000101,第二个集合可以转换为 10001000。 怎么转的?没看懂

    作者回复: 10000101最高位(第8位)的1表示集合中的8,第3位的1表示集合中的3,最低位的1表示集合中的1,以此类推。然后两个集合的交集就专为两个二进制数的按位与

    2018-12-26
    3
  • 风轨
    不等关系是“最没用”的关系,没有传递性,更没有序性。 如果没有额外空间,直接暴力比较,时间复杂度O(n平方); 如果这n个数字本身是有序的,需要时间复杂度O(n),排序时间复杂度O(nlog(n))。 如果额外空间充足,在数据聚集度较高甚至连续时,可以使用桶,时间复杂度O(n);如果数据很分散,数据范围远远大于数据量,可以考虑用桶加hash,时间复杂度O(n),但需要考虑hash碰撞问题。

    作者回复: 很好的总结!

    2018-12-26
    2
  • I keep my ideals💤
    不太明白,1到n不就是所有数吗,所有数异或所有数不就是0了吗😔😔😔

    作者回复: 原题可能没有说清楚,非重复的数字只异或一次,所以为0,而重复的数字会异或两次,成为最后的结果。

    2019-06-28
    1
收起评论
大纲
固定大纲
位操作的应用实例
1. 验证奇偶数
2. 交换两个数字
显示
设置
留言
61
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部