【位运算】二进制状态压缩、成对变换、lowbit运算

这篇具有很好参考价值的文章主要介绍了【位运算】二进制状态压缩、成对变换、lowbit运算。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、二进制状态压缩

二进制状态压缩,是指将一个长度为 m m mbool 数组用一个 m m m 位二进制整数表示并存储的方法。

利用下列位运算操作可以实现原 bool 数组中对应下标元素的存取。

操作 运算
取出整数 n n n 在二进制表示下的第 k k k (n >> k) & 1
取出整数 n n n 在二进制表示下的第 0 0 0 ~ k − 1 k - 1 k1 n & ((1 << k) - 1)
把整数 n n n 在二进制表示下的第 k k k 位取反 n ^ (1 << k)
对整数 n n n 在二进制表示下的第 k k k 位赋值 1 n | (1 << k)
对整数 n n n 在二进制表示下的第 k k k 位赋值 0 n & (~(1 << k))

这种方法运算简便,且节省了程序运行的时间和空间。当 m m m 不太大时,可以直接使用一个整数类型存储。当 m m m 较大时,可以使用若干个整数类型(int数组),也可以直接利用 C++ STL 提供的 bitset 实现。

2、成对变换

对于非负整数 n n n

  • n n n 为偶数时,n ^ 1 等于 n + 1 n + 1 n+1
  • n n n 为偶数时,n ^ 1 等于 n − 1 n - 1 n1

因此,“0 与 1” “2 与 3” “4 与 5” … 关于 ^ 1 运算构成 “成对变换”。

这一性质经常用于图论邻接表中边集的存储。在具有无向边(双向边)的图中把一对正反方向的边分别存储在邻接表数组的第 n n n n + 1 n+1 n+1 位置(其中 n n n 为偶数),就可以通过 ^ 1 的运算获得与当前边 ( x , y ) (x, y) (x,y) 反向的边 ( y , x ) (y, x) (y,x) 的存储位置。

3、lowbit运算

lowbit(n) 定义为非负整数 n n n 在二进制表示下 “最低位的 1 及其后边所有的 0” 构成的数值。 n = 10 n = 10 n=10 的二进制表示为 ( 1010 ) 2 (1010)_2 (1010)2,则 l o w b i t ( n ) = 2 = ( 10 ) 2 lowbit(n) = 2 = (10)_2 lowbit(n)=2=(10)2

推导 l o w b i t ( n ) lowbit(n) lowbit(n) 的公式。

n > 0 n > 0 n>0 n n n 的第 k k k 位是 1,第 0 0 0 ~ k − 1 k-1 k1 位都是 0。

为了实现 lowbit 运算,先把 n n n 取反,此时的第 k k k 为变成 0,第 0 0 0 ~ k − 1 k-1 k1 位都是1。再令 n = n + 1 n = n + 1 n=n+1,此时因为进位,第 k k k 为变为1,第 0 ~ k − 1 k-1 k1 位都是0。

在上面取反加1操作后, n n n 的第 k + 1 k+1 k+1 位到最高位恰好与原来相反,所以 n & (~n+1) 仅有第 k k k 位为1,其余位都是0。而在补码表示下,~n = -1 - n,因此

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

lowbit 运算配合 Hash 可以找出整数二进制表示下所有是 1 的位,所花费的时间与 1 的个数同级。 为达该目的,只需不断把 n 赋值为 n - lowbit(n),直至 n = 0 n=0 n=0

例如,n = 9 = (1001)2,则 lowbit(9) = 1。把 n 赋值为 9 - lowbit(9) = 8 = (1000)2,则 lowbit(8) = 8 = (1000)2。此时 8 - lowbit(8) = 0,停止循环。在整个过程中减掉了 1 和 8 = (1000)2 两个数,它们恰好是 n 每一位上的 1 后面补 0 得到的数值。取 1 和 8 的对数 log21 和 log28,即可得知 n n n 的第 0 位和第 3 位是 1。 因为 C++ math.h 库的 log 函数是以 e 为底的实数运算,并且复杂度常数较大,所以需要预处理一个数组,通过 Hash 的方法代替 log 运算。

当 n 较小时,最简单的方法是直接建立一个数组 H,令 H[2k] = k,程序如下:

const int MAX_N = 1 << 20;
int H[MAX_N + 1];
for (int i = 0; i <= 20; i++) H[1 << i] = i; //预处理
while (cin >> n) {
	while (n > 0) {
		cout << H[n & -n] << ' ';
		n -= n & -n;
	}
	cout << endl;
}

稍微复杂但效率更高的方法是建立一个长度为 37 的数组 H,令 H[2 k mod 37] = k。这里利用了一个小的数学技巧: ∀ k ∈ [ 0 , 35 ] , 2 k \forall k \in [0,35], 2^k k[0,35],2k mod 37 互不相等,且恰好取遍1 ~ 36。需要之后的程序为:

int H[37];
for (int i = 0; i < 36; i++) H[(1ll << i) % 37] = i;

while (cin >> n) {
	while (n > 0) {
		cout << H[n & -n] << ' ';
		n -= n & -n;
    }
    cout << endl;
}

值得指出的是,lowbit运算也是树状数组中的一个基本运算。文章来源地址https://www.toymoban.com/news/detail-717290.html

到了这里,关于【位运算】二进制状态压缩、成对变换、lowbit运算的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 读数据压缩入门笔记02_二进制和熵

    2024年02月06日
    浏览(85)
  • 【第36天】组合位运算训练 | 二进制思想

    本文已收录于专栏 🌸《Java入门一百例》🌸

    2024年02月01日
    浏览(36)
  • 深入解析位运算算法:探索数字的二进制秘密

    位运算是计算机科学中的重要概念,用于在二进制数字层面进行各种操作。本文将深入介绍位运算的基本操作,以及它在判断、计算和处理数字中的应用,包括判断2的幂次方、位图法、位掩码和寻找缺失数字等。 位操作是通过对数字的二进制表示进行操作,实现各种功能。

    2024年02月11日
    浏览(42)
  • ( 位运算 ) 190. 颠倒二进制位 ——【Leetcode每日一题】

    难度:简单 颠倒给定的 32 位无符号整数的二进制位。 提示: 请注意,在某些语言(如 Java )中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是

    2024年02月03日
    浏览(45)
  • C#对象二进制序列化优化:位域技术实现极限压缩

    目录 1. 引言 2. 优化过程 2.1. 进程对象定义与初步分析 2.2. 排除Json序列化 2.3. 使用BinaryWriter进行二进制序列化 2.4. 数据类型调整 2.5. 再次数据类型调整与位域优化 3. 优化效果与总结 在操作系统中,进程信息对于系统监控和性能分析至关重要。假设我们需要开发一个监控程序

    2024年01月22日
    浏览(45)
  • 【FPGA】Verilog:二进制并行加法器 | 超前进位 | 实现 4 位二进制并行加法器和减法器 | MSI/LSI 运算电路

    0x00 并行加法器和减法器 如果我们要对 4 位加法器和减法器进行关于二进制并行运算功能,可以通过将加法器和减法器以 N 个并行连接的方式,创建一个执行 N 位加法和减法运算的电路。 4 位二进制并行加法器 4 位二进制并行减法器

    2024年02月05日
    浏览(55)
  • 码出高效_第一章 | 有意思的二进制表示及运算

    设想有8条电路,每条电路有高电平和低电平两种状态,即就有2 8 =256种不同的信号。假设其表示区间为0~255,最大数即2 8 -1。 那么32条电路能够表示最大数为(2 32 -1)=4294967295,即所谓的32位电路信号。 正负数表示: 上面的8条电路,最左侧一条表示正负:0-整数,1-负数,不

    2024年02月06日
    浏览(36)
  • 关于二进制的原码、补码和反码,以及表示范围、常见位运算符和进制转换的理解与简述

    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/17963363 出自【进步*于辰的博客】 参考笔记一,P3.13、P5.1;笔记三,P43.1/3、P44.1。 注:我暂且没有整理关于二进制、原码、补码和反码等概念的理论,本文中的阐述都基于

    2024年02月02日
    浏览(46)
  • (位运算) 1356. 根据数字二进制下 1 的数目排序 ——【Leetcode每日一题】

    难度:简单 给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。 如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。 请你返回排序后的数组。 示例 1: 输入 :arr = [0,1,2,3,4,5,6,7,8] 输出 :[0,1,2,4,8,3,5,6,7] 解释

    2024年02月12日
    浏览(47)
  • 剑指 Offer 15. 二进制中1的个数 / LeetCode 191. 位1的个数(位运算)

    链接:剑指 Offer 15. 二进制中1的个数;LeetCode 191. 位1的个数 难度:简单 编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。 提示: 请注意,在某些语言(如 Java)中,没有无符号整数类型。

    2024年02月12日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包