JavaScript 位运算总结&拾遗
最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识。
把一个数变为大于等于该数的最小的2的幂
一个数为2的幂,那么该数的二进制码只有最高位是1。
根据这个性质,我们来举个栗子,比如有数字10,转为二进制码后为:
1 0 1 0
我们只需把 0 bit的位置全部用1填充,然后再把该二进制码加1就ok了。而x | (x + 1)
正好可以把最右边的0置为1,可是问题来了,当二进制码变成 1 1 1 1
后,我们无法判断二进制码已经全是1了,继续操作的话会变成1 1 1 1 1
,于是,该法失败...
我们可以采用类似迭代的方法,又有点分组的意思。因为最高位肯定是1,我们把init的数右移一位,和原数作与运算,这样就能把次高位也置为1,然后继续右移,这时最前面两位都是1了,右移两位后,做与运算,这时前四位都是1了:
function change2Pow(n) {
if(!(n & (n-1)) && n > 0) return n;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n + 1;
}
计算二进制中1的个数
leetcode中有一道这样的题目-Number of 1 Bits,正好拿来验证程序的正确性。
常规解法不用多说,直接上代码:
var hammingWeight = function(n) {
var ans = 0;
while (n) {
ans += n & 1;
n >>>= 1;
}
return ans;
};
因为题目中有说是unsigned int32的整数,所以要用有符号右移>>>
来操作符号位。
位运算解法和求逆序一样,也采用分组的思想。
我们以16位下的12345举例(6个1),先写出它的二进制码表示:
0011000000111001
第一步:每两个为一组,组内高低位相加
00 10 00 00 00 10 01 01
第二步:每四个为一组,组内高低位相加
0010 0000 0010 0010
第三步:每8个为一组,组内高低位相加
00000010 00000100
第四步,每16个为1组,组内高低位相加
0000000000000110
最后得到的数字6即为12345二进制码中1的个数。而实际中,因为int32是32位的,所以一共要进行5步。求解思路和求逆序类似,逆序是要交换,所以要分别左移右移,而求1的个数是相加,所以只需移动一次就够了。
完整代码:
var hammingWeight = function(n) {
n = ((n & 0xAAAAAAAA) >>> 1) + (n & 0x55555555);
n = ((n & 0xCCCCCCCC) >>> 2) + (n & 0x33333333);
n = ((n & 0xF0F0F0F0) >>> 4) + (n & 0x0F0F0F0F);
n = ((n & 0xFF00FF00) >>> 8) + (n & 0x00FF00FF);
n = ((n & 0xFFFF0000) >>> 16) + (n & 0x0000FFFF);
return n;
};
因为是unsigned int32,所以要用>>>
如前所述。
再次击败100%的JavaScript code...
计算二进制中1的个数的奇偶性
我们可以先计算1的个数,然后再判断奇偶。当然既然作为一道独立的题目,肯定有更简便的方法。
整个过程可以用分治来解。第1步统计相邻2位的1的个数奇偶性,保存到这2位的低位中。第2步统计相邻4位的1的个数奇偶性,保存到这4位的低位中。……第5步统计相邻2位的1的个数奇偶性,保存到这32位的低位中,即x的最低位。
function bit1OddEven(x){ //奇数个为1,偶数个为0
x ^= x >>> 1; //相邻 2位中1的奇偶性
x ^= x >>> 2; //相邻 4位中1的奇偶性
x ^= x >>> 4; //相邻 8位中1的奇偶性
x ^= x >>> 8; //相邻16位中1的奇偶性
x ^= x >>> 16; //相邻32位中1的奇偶性
return x & 1;
}
统计二进制前导0、末尾0的个数
先排除为0的特殊情况。然后先看前16位是否全0,如果全0,增加计数,并把这个数左移16位删除已经计数的16个0。然后看前8位是否全0。一直到只剩一位时可以直接计算。整个过程的核心是二分思想。
统计末尾0的个数时思想类似,只是变成了统计后面16位、8位等是否全0。
function countLeading0(x) {
if (!x) return 32;
var n = 1;
if ((x >>> 16) == 0) n += 16, x <<= 16;
if ((x >>> 24) == 0) n += 8, x <<= 8;
if ((x >>> 28) == 0) n += 4, x <<= 4;
if ((x >>> 30) == 0) n += 2, x <<= 2;
return n - (x >>> 31);
}
function countTrailing0(x) {
if (!x) return 32;
var n = 1;
if ((x << 16) == 0) n += 16, x >>>= 16;
if ((x << 24) == 0) n += 8, x >>>= 8;
if ((x << 28) == 0) n += 4, x >>>= 4;
if ((x << 30) == 0) n += 2, x >>>= 2;
return n - (x & 0x01);
}
当然计算末尾0的个数,我们也可以这样:
function countTrailing0(a) {
return Math.log(a & (-a)) / Math.LN2;
}
这个系列暂时结束了,但我知道对于位运算的学习,这只是起点。
附位运算系列目录:
- javascript 位运算
- 常用位运算整理
- 【位运算经典应用】 标志位与掩码
- 【位运算经典应用】 N皇后问题
- 【位运算经典应用】 求二进制逆序
- 【位运算经典应用】 寻找那个唯一的数
- leetcode - 位运算题目汇总(上)
- leetcode - 位运算题目汇总(下)
- JavaScript 位运算总结&拾遗
JavaScript 位运算总结&拾遗的更多相关文章
- 位运算总结&拾遗
JavaScript 位运算总结&拾遗 最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识 ...
- javascript位运算
javascript作为一门高级语言,他尽量让开发人员减少思考底层的硬件工作原理,而将精力集中在逻辑开发的层面.不过,不论这门语言多么高级,我们必须知道数据依然以bits的形式存储,有时候我们会直接与 ...
- javascript 位运算
位运算博大精深,本文总结下基本的位运算的概念. 1.整数的二进制码 位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值.ECMAScript中的所有数值都以IEEE-754 64位格式存储 ...
- leetcode - 位运算题目汇总(下)
接上文leetcode - 位运算题目汇总(上),继续来切leetcode中Bit Manipulation下的题目. Bitwise AND of Numbers Range 给出一个范围,[m, ...
- javascript的变态位运算
javascript的变态位运算 var a = "10" | 0; alert(a); alert (typeof a);结果为10,number. 这就是说这条语句可以将字符串 ...
- 【JavaScript】进制转换&位运算,了解一下?
前言 在一般的代码中很少会接触到进制和位运算,但这不代表我们可以不去学习它.作为一位编程人员,这些都是基础知识.如果你没有学过这方面的知识,也不要慌,接下来的知识并不会很难.本文你将会学习到: 进制转 ...
- javascript中的类型转换(进制转换|位运算)
1:parseInt(string) : 这个函数的功能是从string的开头开始解析,返回一个整数 parseInt("123hua"); //输出 123 parseInt(& ...
- javascript中的位运算,
罗浮宫群里又有讨论位运算符号|了,做过一段时间php,数据库保存布尔值数据经常用到,比如100110 就表明了六个属性的是与否,极大减少了数据量..] ECMAScript 中位运算跟其他语言一样的. ...
- js中的位运算
按位运算符是把操作数看作一系列单独的位,而不是一个数字值.所以在这之前,不得不提到什么是"位": 数值或字符在内存内都是被存储为0和 1的序列,每个0和1被称之为1个位,比如说10 ...
随机推荐
- JavaScript Patterns 6.3 Klass
Commonalities • There’s a convention on how to name a method, which is to be considered the construc ...
- SQL Server 2012实施与管理实战指南(笔记)——Ch5启动SQL Server服务和数据库
5.启动SQL Server服务和数据库 在数据库和服务启动过程中,经常会出现的问题: 1.SQL Server实例无法正常启动 2.系统数据库无法正常启动 3.网络配置失败 4.用户数据库无法启动 ...
- 定时器的应用---中断方式---让8个LED灯,左右各4个来回亮
定时器的应用---中断方式---让8个LED灯,左右各4个来回亮 /*************************** 中断方式 是主程序专注于其他的事情, 待定时器中断时才执行中断子程序. ** ...
- 浅谈 Linux 内核无线子系统
浅谈 Linux 内核无线子系统 本文目录 1. 全局概览 2. 模块间接口 3. 数据路径与管理路径 4. 数据包是如何被发送? 5. 谈谈管理路径 6. 数据包又是如何被接收? 7. 总结一下 L ...
- AI (Adobe Illustrator)详细用法(四)
本节主要是介绍和形状相关的操作. 一.外观面板的使用 熟悉外观面板的使用很重要. 1.新增描边 外观面板可以让我们增加多个描边. 点击“新增描边”,系统自动添加一个描边. 选中文字,新增描边,可以修改 ...
- git 学习使用总结二(远程仓库操作)
这篇文章仅供自己以后翻阅加深记忆,要系统的学习 git 教程(中文版),请移步到 liaoxuefeng.com 学习 git 教程部分. 我使用的是 windows 系统,所以使用 Git Bash ...
- 【一周读书】All life is problem solving
书籍:<开放的智力> 采铜是我在知乎关注最早的大V之一,那时我脑里有一大堆疑惑和问题,是他的答案帮助我理清了思绪.我从他身上学习到对书籍的爱好,对思维方法的关注,对智慧的向往.读这本小集子 ...
- 《Writing Idiomatic Python》前两部分的中文翻译
汇总了一下这本小书前两部分的内容: 翻译<Writing Idiomatic Python>(一):if语句.for循环 翻译<Writing Idiomatic Python> ...
- POJ1129Channel Allocation[迭代加深搜索 四色定理]
Channel Allocation Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 14601 Accepted: 74 ...
- Visio连接数据表实体外键[快捷记录]
打开数据库模型图. 单击“常用”工具栏上的“连接线”工具. 将“连接线”工具放在父表的中心上,使表的四周出现轮廓线,然后拖到子表的中心.当子表出现轮廓线时,松开鼠标按钮. 两个连接点均变为红色,同时父 ...