Java.Integer.bitCount(int)源码解析

news/2024/4/26 14:10:50/文章来源:https://blog.csdn.net/qq_43164662/article/details/128094430

bitCount

  • 前言
  • 一、由易到难,头脑热身
  • 二、简单优化,一题多解
  • 三、分治优化
  • 四、bitCount(int)源码优化
  • 总结
  • 参考文献

前言

如何求解一个二进制中1的个数?有常规的O(N)法,还有基于分治的O(logN),即Java的bitCount(int)方法。
对于bitCount(int)源码,是已经优化过的代码,已经看不到原始的分治逻辑,显的很难。但从分治原理到优化,思路非常简单,感受分治的魅力,感受挖掘规律进行优化的魅力。
所有的困难都是由简单知识点结合内部逻辑联系组合而成!

一、由易到难,头脑热身

如何求二进制中1的个数?常规的方法就是对每位二进制进行判定累计。

 	public int hammingWeight(int n) {int cnt = 0;for(int i = 0;i < 32;i++){if((1 << i & n) != 0) ++cnt;}return cnt;}

二、简单优化,一题多解

如果二进制计算基础,即常见位运算,那基本知道如何快速将最后一个1消掉。n - 1会导致二进制最后一个1被借用,其后的0全部变为1,如8 = 0x1000,8 - 1 = 7 = 0x0111; 那么n & (n - 1)就能把最后一个1消掉,如0x1000 & 0x0111 = 0x0000;

	public int hammingWeight(int n) {int cnt = 0;while(n != 0){++cnt;n = n & (n - 1);}return cnt;}

这样就能减少判定次数,而且没有if判定。

三、分治优化

15 = 1111,如何分治计算1的个数,直接统计1的个数即可,即不断做加法即可。
在这里插入图片描述

提取关键问题,如何让前一位和后一位做加法呐
直接将二进制无符号右移一位,前后两位不就对齐了吗?再用0101…来将左边多余的二进制抹除,再进行最终的加法运算。
0101 = 5,所以需要用5来抹除多余的1.

n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);

统计了1位,接下来统计2位,再统计4位,继续统计8位 / 16位,都是同样的道理,直接通过无符号右移不同的位数进行加法统计即可。

public int hammingWeight(int n) {// 用0101来抹除多余的1 + 右移1位对齐。n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);// 用0011来抹除多余的1 + 右移2位对齐。n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);// 用00001111来抹除多余的1 + 右移4位对齐。n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);// 用0000000011111111来抹除多余的1 + 右移8位对齐。n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);// 用00000000000000001111111111111111来抹除多余的1 + 右移16位对齐。n = (n & 0x0000ffff) + ((n >> 16) & 0x0000ffff);return n;}

四、bitCount(int)源码优化

上面就是bitCount的分治原理,再深入挖掘二进制的规律,挖掘计算中的个性,来做一个优化。

  1. 用0101来抹除多余的1 + 右移1位对齐。
    n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
    对于两位二进制来讲,0x11 - 0x01 = 0x10 = 2,表示有2个1,0x10 - 0x01 = 0x01 = 1表示有1位二进制,就是这么巧!
    0x11 >>> 1 = 0x01;0x10 >>> 1 = 0x01;
    对于第2为为0的情况,自然不用管,毕竟0x01 - 0x00 = 1;0x00 - 0x00 = 0;
    所以可以用减法,少一次与运算,n = n - ((n >>> 1) & 0x55555555)

  2. 用0011来抹除多余的1 + 右移2位对齐。
    n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
    无法优化,没有二进制规律,而且最多4个1需要3位二进制表示。

  3. 用00001111来抹除多余的1 + 右移4位对齐。
    n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
    这里需要统计的是1byte中1的个数,而1的个数最多有8个,4位二进制完全够用了,所以可以先做加法运行,再对多余的0进行抹除,来减少一次运算。即n = (n + (n >>> 4)) & 0x0f0f0f0f;

第4/5点同理,但是从第4点开始,就有8位的空间来统计二进制数,而int只有32位,只需6个bit可以完成统计,所以可进一步优化!
先不管多余的二进制(未对齐的错误运算),最后统一把其抹除,只用6bit即可,所以用0x111111 = 0x3f来抹除多余的二进制。

疑问:为什么4位时不行?而8/16位可以呐?还是回归到6bit足够表示32位二进制个数了,4bit不行,下次运算时,紧挨着的2bit被运算,而且还抹不掉这个未对齐的错误运算!

bitCount源码,即最终优化过的代码,

/*** Returns the number of one-bits in the two's complement binary* representation of the specified {@code int} value.  This function is* sometimes referred to as the <i>population count</i>.** @param i the value whose bits are to be counted* @return the number of one-bits in the two's complement binary*     representation of the specified {@code int} value.* @since 1.5*/@HotSpotIntrinsicCandidatepublic static int bitCount(int i) {// HD, Figure 5-2i = i - ((i >>> 1) & 0x55555555);i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);i = (i + (i >>> 4)) & 0x0f0f0f0f;i = i + (i >>> 8);i = i + (i >>> 16);return i & 0x3f;}

总结

1)分治统计,从O(N)降到O(logN)。
2)从易到难,一步步挖掘内在规律和个性,一步步优化,完成经典之作。
3)所有困难都是由简单知识点和它们之间的内在逻辑联系构成!

参考文献

[1] LeetCode 位1的个数
[2] bitCount 源码解析
[3] JDK 12

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

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

相关文章

我们为什么喜欢看疯狂科学家开飞艇?

很多人可能不是科幻迷&#xff0c;也在日常生活中接触过蒸汽朋克。为什么呢&#xff1f;很简单——蒸汽朋克几乎无处不在。相比其他科幻流派&#xff0c;蒸汽朋克可能算是最“出圈”的一种。简单地说&#xff0c;蒸汽朋克是一种科幻小说类型&#xff0c;由“蒸汽 ”(steam)和“…

《论文阅读》DeepSFM: Structure From Motion Via Deep Bundle Adjustment

留个笔记自用 DeepSFM: Structure From Motion Via Deep Bundle Adjustment 做什么 首先是最基础的&#xff0c;Structure-from-Motion&#xff08;SFM&#xff09;&#xff0c;SFM可以简单翻译成运动估计&#xff0c;是一种基于dui8序列图片进行三维重建的算法。简单来说就…

移动跨平台开发跨家选型参考建议

从 iPhone 诞生至今&#xff0c;智能手机风靡全球已将近20年&#xff0c;智能手机操作系统 iOS 和 Android 也成为当仁不让的顶流般的存在&#xff0c;而作为其背后的灵魂&#xff0c;移动应用也随着技术的发展已经越来越丰富。如果从技术层面来讲&#xff0c;移动 App 也从最开…

(1)点云库PCL学习——点云的格式、PCD文件的打开和显示

1、主要参考 (1)格式说明&#xff1a; 点云库PCL学习——点云的格式、PCD文件的打开和显示 ROS知识&#xff1a;点云文件.pcd格式_无水先生的博客-CSDN博客_pcd文件 &#xff08;2&#xff09;点云滤波&#xff0c;对nan的滤波 Python点云数据处理(三)滤波与RANSAC分割 - …

省 市 县 三级联动

大纲 一、导入省市县数据表(t_region) 二、引入jar包 三、导入所需util类&#xff08;整体框架&#xff09; 四、编写代码 1、配置数据库相关信息(数据库名、用户名、密码) config.propreties #oracle9i #driveroracle.jdbc.driver.OracleDriver #urljdbc:oracle:thin:loca…

jsp393学生宿舍管理系统mysql

两个权限 管理员和 学生 1. 学生信息管理 添加学生信息&#xff08;学生号&#xff0c;姓名 院系 班级入学日期 &#xff09;修改学生信息 学生退宿舍&#xff08;可以删除指定的学生也可以成批删除&#xff09; 2. 宿舍信息管理 宿舍的基本信息&#xff08;公寓数 宿舍…

第五届“强网”拟态防御国际精英挑战赛——特邀战队篇

第五届“强网”拟态防御国际精英挑战赛即将在南京隆重开赛&#xff01;本届大赛面向全球顶尖CTF战队&#xff0c;在创新应用场景与技术的基础上&#xff0c;拓展升级赛道&#xff0c;全面覆盖典型网络设备。大赛汇集国内外60支精英战队&#xff0c;参赛阵容、数量再创新高。 本…

科普下抖音的规则,为什么别人的内容很容易火,而我的很难?

今天给大家科普下抖音的规则&#xff0c;为什么别人的内容很容易火&#xff0c;而我的很难&#xff1f; 上一篇给大家讲了现在做抖音还来得及么&#xff1f;肯定的回答&#xff0c;一直都来得及。 既然来得及&#xff0c;那么我们怎么才能做好抖音呢&#xff1f; 在我看来&a…

5 - 2 单选题

1.下列线索二叉树中&#xff08;用虚线表示线索&#xff09;&#xff0c;符合后序线索树定义的是&#xff1a;B 后序线索二叉树的构建流程就是&#xff1a; 1.后序遍历二叉树&#xff1a;d b c a 2.第一个结点的前驱是NULL&#xff0c;即d的前驱&#xff0c;d的左孩子为NULL …

web表单(详解)

目录 1. 表单的概述 1.1 表单组成 2. 表单标记 2.1 input标记 2.2 select标记 2.3 textarea标记 3.HTML5新增标记 3.1 datalist标记 3.2 date 输入类型 3.3 color输入类型 3.4 button标记 3.5 details标记和summary标记 3.6 progress标记 3.7 meter标记 4 综合…

云原生微服务治理技术朝无代理架构的演进之路

摘要&#xff1a;本文基于对微服务治理技术从SOA, 微服务框架&#xff0c;到云原生架构的历史发展总结&#xff0c;提出了一种新的基于Javaagent技术的新一代无代理架构的服务治理技术&#xff0c;并介绍了其相关的代表性开源项目Sermant。本文分享自华为云社区《云原生微服务治…

Docker安装Redis集群失败经历汇总

在程序员的开发过程中&#xff0c;Redis可以说基本上是必不可少的缓存中间件。不管是二进制包还是docker安装Redis的文章在网上都是数不胜数。我之前自己玩Redis的时候基本不是二进制包安装就是docker安装&#xff0c;也没有尝试过集群方式。每次需要的时候&#xff0c;网上百度…

Cloud-computing 实验镜像 chinaskills_cloud_iaas.iso chinaskills_cloud_paas.iso

Cloud-computing 实验镜像 最近因新项目再次进行云计算环境的搭建&#xff0c; 找这两个镜像&#xff08; 找chinaskills_cloud_paas.iso chinaskills_cloud_iaas.iso&#xff09;颇为费劲&#xff0c;用尽九牛二虎之力总算找到了&#xff0c;该大侠还分享了诸多系统镜像和完…

Centos7搭建SVN代码控制服务器

Centos7搭建SVN代码控制服务器检查SVN是否安装创建SVN版本库配置代码库设置允许访问远程仓库的用户帐号密码设置权限控制设置SVN服务配置启动svn与停止启动SVN关闭SVN访问拉取远程仓库代码检查SVN是否安装 1、centos7系统自带SVN rpm -qa subversion2、如果没有则通过yum安装 …

Day15--加入购物车-初始化vuex

1.加入购物车&#xff1a; 我的操作&#xff1a; ************************************************************************************************************* 2.购物车里面的商品数据在多个页面都会用到。所以把购物车里面的商品数据存储在vuex里面&#xff0c; 我的…

Windows10安装配置allure

1、allure官方文档&#xff1a; https://docs.qameta.io/allure/#_about 官方文档中&#xff0c;windows部署allure步骤&#xff1a; 奈何提示scoop不是內部命令 2、安装scoop scoop官方文档&#xff1a;https://scoop.sh/ 需要打开power shell&#xff0c;执行提示的两条…

外汇天眼:英国研究人员与南非合作应对气候变化

随着南非对气候变化的担忧加剧&#xff0c;英国卫生部已同意与南非就九个不同项目组建一个合作研究团队&#xff0c;旨在拯救生命。 南非总统西里尔拉马福萨 (Cyril Ramaphosa) 与英国卫生大臣在克里克研究所会面后达成了合作协议&#xff0c;克里克研究所如今被称为欧洲最大的…

BUUCTF Misc 来首歌吧 荷兰宽带数据泄露 面具下的flag 九连环

来首歌吧 下载文件 使用Audacity打开 可以发现框出来的一串,放大查看 有长有短有空格&#xff0c;大概率是摩斯密码 ...../-.../-.-./----./..---/...../-..../....-/----./-.-./-.../-----/.----/---../---../..-./...../..---/./-..../.----/--.../-../--.../-----/----./.…

汽车蓄电池低压报警设计

目 录 摘 要 I Abstract II 第一章 绪论 1 1.1 选题背景及意义 1 1.2 国内外发展状况 2 1.2.1国内发展现状 2 1.2.2 国外蓄电池监测系统研究现状 2 1.3 研究主要内容 4 第2章 系统总体设计与算法确定 5 2.1 监测系统总体设计原理 5 2.2 主控芯片的选择 6 2.2.1 89C51单片机的概…

IPv6进阶:IPv6 过渡技术之IPv6 over IPv4 手动隧道

实验拓扑 R1-R3-R2之间的网络为IPv4环境&#xff1b;PC1及PC2处于IPv6孤岛。 实验需求 R1及R2为IPv6/IPv4双栈设备&#xff1b;在R1及R2上部署IPv6 over IPv4手工隧道使得PC1及PC2能够互相访问。 配置及实现 R3的配置如下 [R3] interface GigabitEthernet0/0/0 [R3-Gigabi…