从集合论到位运算

前言


本文将扫清位运算的迷雾,在集合论与位运算之间建立一座桥梁。

在高中,我们学了集合论(set theory)的相关知识。例如,包含若干整数的集合 S={0,2,3}。在编程中,通常用哈希表(hash table)表示集合。例如 Java 中的 HashSet,C++ 中的 std::unordered_set。

在集合论中,有交集 ∩、并集 ∪、包含于 ⊆等等概念。如果编程实现「求两个哈希表的交集」,需要一个一个地遍历哈希表中的元素。那么,有没有效率更高的做法呢?

该二进制登场了。

集合可以用二进制表示,二进制从低到高第 i 位为 1表示 i 在集合中,例如集合{0,2,3}可以用二进制1101表示;反过来,1101就对应集合{0,2,3}。正式地说,包含非负整数的集合S可以用以下方式压缩成一个数字:

                                                       f(S) = \sum_{i\in s}^{} 2^i

例如集合{0,2,3}可以压缩成2^0 + 2^2 + 2^3 = 13也就是二进制的1101。

利用位运算「并行计算」的特点,我们可以高效地做一些和集合有关的运算。按照常见的应用场景,可以分为以下四类:

  1. 集合与集合
  2. 集合与元素
  3. 遍历集合
  4. 枚举集合

一、集合与集合


其中 & 表示按位与,∣ 表示按位或,⊕ 表示按位异或,∼ 表示按位取反。

两个集合的「对称差」是只属于其中一个集合,而不属于另一个集合的元素组成的集合,也就是不在交集中的元素组成的集合。

术语集合位运算集合示例位运算示例
交集A∩Ba&b{0,2,3}∩{0,1,2} = {0,2}1101 & 0111 = 0101
并集A∪Ba ∣ b{0,2,3}∪{0,1,2} = {0,1,2,3}1101 | 0111 = 1111
对称差A Δ Ba⊕b{0,2,3}Δ{0,1,2} = {1,3}1101 ⊕ 0111 = 1010
A\Ba&∼b{0,2,3}\{1,2} = {0,3}1101 & 1001 = 1001

二、集合与元素

通常会用到移位运算。

其中 << 表示左移,>> 表示右移。

术语集合位运算集合示例位运算示例
空集0
单元素集合{i}1<<i{2}1<<2
全集U={0,1,2,⋯n−1}(1<<n)-1{0,1,2,3}(1<<4)-1
补集Cu​S=U\S((1<<n)-1)⊕sU={0,1,2,3}
Cu{1,2}={0,3}
1111 ⊕ 0110 = 1001
属于i \in S(s >> i) & 1=12 \in [{0,2,3}](1101 >> 2) & 1=1
不属于i \notin S(s >> i) & 1=01\notin [0,2,3](1101 >> 1) & 1=0
添加元素S∪{i}s | (1<<i){0,3}∪{2}1001 ∣ (1 << 2)
删除元素S \ {i}s&∼(1 << i){0,2,3}\{2}1101&∼(1 << 2)

特别地,如果 𝑠 是 2 的幂,那么 𝑠 &( 𝑠 − 1) =0。

此外,编程语言提供了一些和二进制有关的库函数,例如:

  • 计算二进制中的 1 的个数,也就是集合大小;
  • 计算二进制长度,减一后得到集合最大元素;
  • 计算二进制尾零个数,也就是集合最小元素。

三、遍历集合

设元素范围从0到n-1,挨个判断每个元素是否在集合s中

for (int i = 0; i < n; i++) {if ((s >> i) & 1) { // i 在 s 中// 处理 i 的逻辑}
}

四、枚举集合

枚举所有集合

设元素范围从 0 到 n−1,从空集 ∅ 枚举到全集 U:

for (int s = 0; s < (1 << n); s++) {// 处理 s 的逻辑
}

枚举非空子集

设集合为 𝑠,从大到小枚举 𝑠 的所有非空子集 sub:

for (int sub = s; sub; sub = (sub - 1) & s) {// 处理 sub 的逻辑
}

为什么要写成 sub = (sub - 1) & s 呢?

暴力做法是从s开始,不断减一,直到0但这样做,中途会遇到很多不是s的子集的情况。例如s=10101时,减1得到10100,这是s的子集,但是再减1就得到10011了。这并不是s的子集。下一个子集应该是10001。

把所有的合法子集按顺序列出来,会发现我们做的相当于「压缩版」的二进制减法,例如

                                10101→10100→10001→10000→00101→⋯

如果忽略掉 10101 中的两个 0,数字的变化和二进制减法是一样的,即

                                        111→110→101→100→011→⋯

如何快速跳到下一个子集呢?比如,怎么从 10100 跳到 10001?

  • 普通的二进制减法,是10100-1=10011,也就是把最低位的1变成0,对于最低位的1右边的0都变成1。
  • 压缩版的二进制减法也是类似的,对于10100->10001,也会把最低位的1变成0,对于最低位的1右边的0,并不是都变成1,只有在s=10101中的1才会变成1。怎么做到?减1后&10101就行,也就是(10100-1)&10101 = 10001

枚举子集(包含空集)

如果要从大到小枚举 𝑠 的所有子集 sub(从 𝑠 枚举到空集 ∅),可以这样写:

int sub = s;
do {// 处理 sub 的逻辑sub = (sub - 1) & s;
} while (sub != s);

原理是当sub=0时(空集),再减1就得到-1,对应的二进制位111...1,在&s就得到了s,所以循环到sub=s时,说明最后一次循环sub=0(空集),s的所有子集都枚举到了。退出循环。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/21000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自然资源-农村土地流转知识全解

自然资源-农村土地流转知识全解 随着农村经济的发展和城市化进程的加快&#xff0c;农村土地面临着多方面的压力&#xff0c;如人口增长、城市扩张、环境恶化等。这些压力导致了农村土地利用率低、经济效益差、农民收入水平低、农村社会经济不发达等问题。因此&#xff0c;改变…

计算机网络学习2

文章目录 信道复用技术 第三章数据链路层概述数据链路层的三个重要问题封装成帧和透明传输差错检测可靠传输的相关基本概念可靠传输的实现机制停止等待协议回退N帧协议选择重传协议 点对点协议PPP共享式以太网网络适配器和MAC地址CSMA_CD协议的基本原理共享式以太网的争用期共享…

备战十一届大唐杯国赛预选赛

这次省赛带了太多个省一了&#xff0c;具体可看下面的图片&#xff0c;只放了一部分。目前根据可靠消息&#xff0c;应该还有个预选赛和去年一样&#xff0c;就是还会考一次仿真。如果说通过了就是国二起步然后去北方工业争夺国一国二&#xff0c;没过的话就是国三。 每…

<MySQL> 表的增删改查 - 基本查询

目录 前言&#xff1a; 一、表的插入 &#xff08;一&#xff09;指定列插入和多行插入 &#xff08;二&#xff09;全列插入 &#xff08;三&#xff09;插入选择更新 &#xff08;四&#xff09;替换数据 二、表中的数据查询 &#xff08;一&#xff09;select查询语…

【SQL学习进阶】从入门到高级应用【三范式】

文章目录 什么是数据库设计三范式三范式一对多怎么设计多对多怎么设计一对一怎么设计最终的设计 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f495;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f495;希望您在这里可以感受到一份…

sql注入-布尔盲注

布尔盲注&#xff08;Boolean Blind SQL Injection&#xff09;是一种SQL注入攻击技术&#xff0c;用于在无法直接获得查询结果的情况下推断数据库信息&#xff1b;它通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信…

低代码选型要注意什么问题?

低代码选型时&#xff0c;确实需要从多个角度综合考虑&#xff0c;以下是根据您给出的角度进行的分析和建议&#xff1a; 公司的人才资源&#xff1a; 评估团队中是否有具备编程能力的开发人员&#xff0c;以确保能够充分利用低代码平台的高级功能和进行必要的定制开发。考察实…

告别繁琐SQL,4K星开源神器让数据库管理像聊天一样简单!

大家好&#xff0c;今天我要给大家介绍一个超级棒的开源项目——SQL Chat。如果你是一名开发者&#xff0c;数据库管理员&#xff0c;或者对数据分析感兴趣&#xff0c;那你绝对不能错过这个神器。SQL Chat&#xff0c;一个近4K星的GitHub项目&#xff0c;它将彻底改变你与数据…

本地安装AI大模型

使用ollmam安装llmama3等模型 1.打开ollmam下载对应系统的软件&#xff0c;安装即可 官网&#xff1a;Ollama&#xff0c; 安装直接点就就行了&#xff0c;没有其他操作 2.安装模型 在官网找到对于的模型下载命令 记录命令:ollama run llama3 打开一个cmd窗口&#xff0c;输…

【已解决】HtmlWebpackPlugin.getHooks is not a function

安装下面的依赖&#xff0c;获得 html-webpack-plugin 的 beta 版本 npm i html-webpack-pluginnext --save此问题在github上有讨论&#xff1a;https://github.com/facebook/create-react-app/issues/5465

【UE5.1 角色练习】09-物体抬升、抛出技能 - part1

前言 在上一篇&#xff08;【UE5.1 角色练习】08-传送技能&#xff09;的基础上继续实现控制物体抬升、抛出的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中新建一个操作映射&#xff0c;这里命名为“Skill_GravityControl”&#xff0c;用按键4触发 2. 通过IK重定向…

git远程仓库限额的解决方法——大文件瘦身

Git作为世界上最优秀的分布式版本控制工具&#xff0c;也是优秀的文件管理工具&#xff0c;它赋予了项目成员对项目进行远程协同开发能力&#xff0c;因此受到越来越多的行业从业人员的喜爱。很多优秀的项目管理平台&#xff0c;比如国内的Gitee&#xff0c;国外的Github&#…

MySQL 一条SQL查询/更新语句是如何执行的?

MySQL 一条SQL查询语句是如何执行的&#xff1f; 1 连接器 首先客户端需要先跟服务端进行连接 2 查询缓存 MySQL 5.7 以及之前的版本会查询MySQL缓存&#xff0c;存储是键值对形式的 分析器 对SQL进行词法分析【会生成词法树】以及语法分析 词法分析&#xff1a; 主要负…

社交媒体数据恢复:淘宝旺信

根据搜索结果&#xff0c;阿里旺旺聊天记录的恢复方法如下&#xff1a; 运行阿里旺旺在旺旺面板底部点击小喇叭图标在打开的消息管理器窗口右上角点击"搜索"点击"高级搜索"设置所需查找的时间段---"搜索" 此外&#xff0c;在阿里旺旺的云存储中…

基于稀疏辅助小波和线性时不变滤波器的惯性传感器步态周期分割方法(MATLAB R2018A)

每个人在肌肉骨骼状况、生理状况、心理特征以及个人行走的“风格”等方面都有各自的特点&#xff0c;因此&#xff0c;每个人都有自己的步态指纹。这意味着可以根据步态特征来进行身份识别。基于步态的身份识别是生物特征识别的一个新兴领域。其机制有3个显著的优点&#xff1a…

STM32高级控制定时器应用之检测输入PWM周期和占空比

目录 概述 1 PWM 输入模式 1.1 原理介绍 1.2 应用实例 1.3 示例时序图 2 使用STM32Cube配置工程 2.1 软件环境 2.2 配置参数 2.3 生成项目文件 3 功能实现 3.1 PWM占空比函数 3.2 输入捕捉回调函数 4 功能测试 4.1 测试软件框架结构 4.2 实验实现 4.2.1 测试实…

整数之间的赋值问题

前言&#xff1a;我们在初学C语言的时候&#xff0c;总是避免不了一些数据类型的转换&#xff0c;例如int-->char&#xff0c;char-->int&#xff0c;如果我们仅仅只学习这些语法&#xff0c;而不去了解底层原理&#xff0c;对于这些输出的内容&#xff0c;我们可能会感觉…

2024还不会安装NodeJs

2024还不会安装NodeJs 1、官网下载 由于本地是windows&#xff0c;所以选择 Prebuilt Installer 64位 NodeJs官网下载 LTS长期支持版本 当然这里我用的 Snipastate 截屏软件&#xff0c;这里也配下载链接 Snipasate下载链接 2、配置环境变量 由于是自己的电脑&#xff0c…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09; 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09;1、设置sping.beaninfo.ignore属性2、…

限流算法整理——滑动窗口限流算法

限流算法描述 滑动窗口限流需要将每个窗口空间划分为无限小的窗口区间&#xff0c;并且动态调整区间的起始点&#xff0c;并且在调整完毕之后需要判断各个区间&#xff0c;累加各个区间的请求&#xff0c;查看是否到达最大的阈值&#xff0c;以此返回允许请求还是拒绝请求 算…