深入剖析 Java 中的 tableSizeFor 方法:通过位运算计算最小的 2 的幂

news2024/9/21 11:13:07

前言

在 Java 的 HashMap 实现中,有一个常用的内部方法 tableSizeFor(int c),它用于计算大于或等于指定整数 c 的最小 2 的幂。这在调整哈希表的容量时尤为重要,保证数组的容量总是 2 的幂次,能使哈希函数运算更加高效。

本文将通过详细分析 tableSizeFor 的源代码,解释其背后的位运算技巧和算法原理,并特别关注其中的一些关键细节,比如为什么位扩展到 16 位时停止。

tableSizeFor 方法的实现

首先,我们来看 tableSizeFor 方法的源码,它存在于 Java 的 HashMap 类中:

private static final int tableSizeFor(int c) {
    int n = c - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

该方法通过位操作来快速计算大于或等于输入值 c 的最小 2 的幂。它的执行效率很高,因为完全依赖于位操作,而非循环或条件判断。接下来,我们逐步解释这段代码的工作原理。

核心算法步骤解析

处理输入值

int n = c - 1;

这里,输入的值 c 被减去 1,这是为了应对输入值刚好是 2 的幂的情况。

举个例子,如果 c 正好是 2 的幂(比如 8、16、32 等),我们需要确保返回的结果还是 c 而不是更大的下一个 2 的幂。

示例:

  • 如果 c = 8c - 1 = 7(二进制表示为 0111)。
  • 如果 c = 10c - 1 = 9(二进制表示为 1001)。

位扩展操作

接下来是一系列位扩展操作,通过右移(>>>)和按位或(|)逐步将 n 的最高位 1 扩展到右边所有的位:

n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;

这些位操作步骤的作用是将 n 的最高有效位 1 扩展到所有更低的位。我们来逐步解析其具体含义。

假设 c = 10,因此 n = 9(二进制 1001)。经过这些步骤后:

  • n |= n >>> 1n 变成 1101,最高的 1 位被扩展到了它右边的 1 位。
  • n |= n >>> 2n 变成 1111,最高两位的 1 扩展到了右边所有位。
  • 后面的位移操作对结果已经没有影响,因为此时所有的低位都已经被填充为 1

为什么进行位扩展

位扩展的目的是将任意整数 n 转换为一个“全 1”的二进制数,即最高位 1 以及它右边的所有位都被设置为 1。这样我们只需在最后一步加 1,就可以得到大于或等于输入值的最小 2 的幂。

例如,1001 经过逐步扩展变成 1111,然后加 1 得到 10000(16),这正是大于 10 的最小 2 的幂。

处理边界条件并返回结果

return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
  • 如果 n 小于 0,返回 1,这是为了防止输入值过小的情况,确保最小值为 1。
  • 如果 n 大于等于 MAXIMUM_CAPACITY,则返回 MAXIMUM_CAPACITY,这是为了防止数组的大小超过哈希表的最大容量。
  • 否则,返回 n + 1,即大于等于 c 的最小 2 的幂。

为什么位扩展到 16 位时就停止了

一个值得注意的细节是,扩展操作最后一行是 n |= n >>> 16,也就是说,位扩展到 16 位时就停止了。那么,为什么在这个时候停止了呢?

32 位整数的限制

在 Java 中,int 类型是一个 32 位的有符号整数,占用 4 字节。因此,无论输入的数字是多少,最多只能用 32 位的二进制数来表示。

为了确保我们扩展到所有可能的位,我们只需要处理最多 32 位。在代码中,通过右移操作逐步扩展位数:

  • n >>> 1:扩展最高 16 位。
  • n >>> 2:扩展最高 8 位。
  • n >>> 4:扩展最高 4 位。
  • n >>> 8:扩展最高 2 位。
  • n >>> 16:扩展最高 1 位。

通过这 5 步操作,整个 32 位整数的所有位都可以被最高位的 1 覆盖。如果再向右移超过 16 位,就没有必要了,因为 32 位整数的所有位已经被扩展完毕。

其他类型的位扩展

如果我们使用的是 64 位的整数(long 类型),那么类似的操作就会继续扩展到 n >>> 32。但是在 32 位的 int 类型中,扩展到 n >>> 16 就足够覆盖所有位了。

示例解析

让我们通过几个示例进一步理解这个算法的工作过程:

输入 c = 5

  • c - 1 = 4(二进制 0100)。
  • 位扩展操作后,n = 0111
  • n + 1 = 8(二进制 1000),返回 8。

输入 c = 17

  • c - 1 = 16(二进制 10000)。
  • 位扩展操作后,n = 11111
  • n + 1 = 32,返回 32。

这些示例展示了 tableSizeFor 的实际效果:它能快速计算出大于等于 c 的最小 2 的幂,避免了循环或条件判断,使得运行时间是常数时间 O(1)。

为什么使用 2 的幂作为哈希表的容量

在哈希表(如 HashMap)中,底层数据结构通常是一个数组,而数组的长度最好是 2 的幂次。这是因为哈希表通常会使用 位运算来计算哈希值的索引位置,而位运算(如 & 操作)比取模运算(%)要快得多。

假设数组长度是 2 的幂次,我们可以通过 h & (n - 1) 来高效地计算元素在数组中的索引,而无需使用相对昂贵的取模操作。这也是 tableSizeFor 方法的重要性所在,它帮助动态扩展哈希表时,始终保持容量为 2 的幂次,从而提升性能。

结语

通过本文的详细解析,我们深入了解了 Java 中 tableSizeFor 方法的实现原理。这个方法利用了巧妙的位操作,能够在常数时间内计算出大于等于给定数值的最小 2 的幂。特别是,位扩展的步骤精心设计到 16 位就停止,是为了匹配 32 位整数的限制,使得算法在效率和正确性上得到了保证。

这个方法广泛应用于哈希表(如 HashMap)中,确保数组容量始终是 2 的幂次,从而能通过位运算快速计算元素的索引,提升哈希表的性能。

位运算是编程中的一项重要技能,特别是在需要优化性能的场景下,像 tableSizeFor 这样的位操作技巧可以大大提高代码的运行效率。

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

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

相关文章

鸿蒙OpenHarmony【轻量系统内核通信机制(互斥锁)】子系统开发

互斥锁 基本概念 互斥锁又称互斥型信号量&#xff0c;是一种特殊的二值性信号量&#xff0c;用于实现对共享资源的独占式处理。 任意时刻互斥锁的状态只有两种&#xff0c;开锁或闭锁。当任务持有互斥锁时&#xff0c;该互斥锁处于闭锁状态&#xff0c;这个任务获得该互斥锁…

从虚拟机安装CentOS到自定义Dockerfile构建tomcat镜像

写在开头 整个过程中涉及的三方软件均来源于三方的官网&#xff0c;因此需要有一个稳定良好的访问公网网络的环境&#xff0c;可能需要科学上网 下载并安装 VMware Workstation Player 下载 需要先注册登录&#xff1a;https://login.broadcom.com/signin 下载页面&#xff1a…

【IoTDB 线上小课 07】多类写入接口,快速易懂的“说明书”!

【IoTDB 视频小课】稳定更新中&#xff01;第七期来啦~ 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源... 一个问题重点&#xff0c;3-5 分钟&#xff0c;我们讲给你听&#xff1a; 一条视频了解写入接口 了解我们的友友们&#xff0c;应该…

HTML粉色烟花秀

目录 系列文章 写在前面 完整代码 代码分析 写在最后 系列文章 序号目录1HTML满屏跳动的爱心&#xff08;可写字&#xff09;2HTML五彩缤纷的爱心3HTML满屏漂浮爱心4HTML情人节快乐5HTML蓝色爱心射线6HTML跳动的爱心&#xff08;简易版&#xff09;7HTML粒子爱心8HTML蓝色…

Observability:构建下一代托管接入服务

作者&#xff1a;来自 Elastic Vishal Raj, Marc Lopez Rubio 随着无服务器&#xff08;serverless&#xff09;的引入&#xff0c;向 Elastic Cloud 发送可观察性数据变得越来越容易。你可以在 Elastic Cloud Serverless 中创建一个可观察性无服务器项目&#xff0c;并将可观察…

Netty对处理粘包和半包的支持

Netty基本介绍&#xff0c;参考 Netty与网络编程 1.1 什么是粘包拆包 例如&#xff1a;发送 ABC&#xff0c; DEF两个报文 收到ABCDEF一个报文&#xff0c;发生了粘包 收到AB&#xff0c;C&#xff0c;DEF三个报文&#xff0c;ABC发生了拆包 收到AB&#xff0c;CD&#xff…

SQL server学习01-SQL server环境配置

目录 一&#xff0c;手动下载及安装 microsoft .net framework 3.5 1&#xff0c;下载 2&#xff0c;安装 二&#xff0c;安装SQL server2014 1&#xff0c;下载 2&#xff0c;安装 3&#xff0c;启动SQL server服务 三&#xff0c;下载及安装Microsoft SQL Server…

2024华为杯研赛E题保姆级教程思路分析

E题题目&#xff1a;高速公路应急车道紧急启用模型 今年的E题设计到图像/视频处理&#xff0c;实际上&#xff0c;E题的难度相对来说较低&#xff0c;大家不用畏惧视频的处理&#xff0c;被这个吓到。实际上&#xff0c;这个不难&#xff0c;解决了视频的处理问题&#xff0c;…

茶思屋直播|TinyEngine+AI:聚焦主航道,在实践中探索低代码技术黑土地

低代码引擎使能开发者定制低代码平台。它是低代码平台的底座&#xff0c;提供可视化搭建页面等基础能力&#xff0c;既可以通过线上搭配组合&#xff0c;也可以通过cli创建个人工程进行二次开发&#xff0c;实时定制出自己的低代码平台。适用于多场景的低代码平台开发&#xff…

周末愉快!——周复盘

加班的晚上有一个美梦&#xff01; 周末愉快简单复盘结尾 精华&#xff1a; 在这个信息爆炸的时代&#xff0c;我们的大脑每天都被无数的数据和刺激充斥&#xff0c;以至于我们常常感到应接不暇。然而&#xff0c;正如古人所言&#xff1a;“不飞则已&#xff0c;一飞冲天”&am…

物联网关组态应用案例

产品简介 拓扑未来物联网关是高集成度的物联网采集及通信装置&#xff0c;支持通过RS485串口以太网口进行数据采集&#xff0c;支持数据缓存、协议解析、边缘计算&#xff0c;Ethernet/4G/WIFI数据传输和接入云端平台。支持采集PLC、传感器、仪器仪表和各种控制器&#xff0c;…

MySQL的索引——提高查找算法的数据结构 B+树

我们MYSQL服务器是在内存中的&#xff0c;所以所有的操作也是内存级的&#xff0c;索引也是如此 我们要提高算法的效率&#xff1a;首先要用一个好的数据存储结构储存数据&#xff0c;然后结构决定算法 所以——索引的本质就是一种提高算法效率组织的数据结构 缩印的主要价值体…

【华为杯】2024数学建模研赛题目

2024数学建模研赛题目已经发布 各个赛题题目如下&#xff1a; A题 B题 C题 D题 E题 F题 赛题完整版在文末&#xff0c;点击下方名片。

【操作系统】01.冯·诺伊曼体系结构

上面这张图就是我们经常能在各种教材中看到的冯诺伊曼体系结构。我们常见的计算机&#xff0c;如笔记本。我们不常见的计算机&#xff0c;如服务器&#xff0c;大部分都遵守冯诺依曼体系。 一、认识设备 输入设备&#xff1a; 键盘、鼠标、网卡、磁盘、摄像头…… 输出设备&a…

Java8 中一个极其强悍的新接口,很多人没用过

在开发过程中经常会使用​​if...else...​​​进行判断抛出异常、分支处理等操作。这些​​if...else...​​​充斥在代码中严重影响了代码代码的美观&#xff0c;这时我们可以利用Java 8的Function接口来消灭​​if...else...​​。 if (...){throw new RuntimeException(&qu…

深入Android UI开发:从自定义View到高级布局技巧的全面学习资料

在Android开发的世界中&#xff0c;UI设计和实现是吸引用户的关键。本文将为您介绍一套全面的Android UI开发学习资料&#xff0c;包括详细的学习大纲、PDF文档、源代码以及配套视频教程&#xff0c;旨在帮助您从自定义View到高级布局技巧&#xff0c;全面提升您的UI开发技能。…

深度学习-从零基础快速入门到项目实践,这本书上市了!!!

此书地址&#xff1a; 《【2024新书】深度学习 从零基础快速入门到项目实践 文青山 跟我一起学人工智能 机器学习算法原理代码实现教程 深度学习项目分析 深度学习 从零基础快速入门到项目实践》【摘要 书评 试读】- 京东图书 除深度学习外我还写了一本软件测试书。我大概是国…

Godot游戏如何提升触感体验

在游戏世界中&#xff0c;触感体验至关重要&#xff0c;既能极大提升玩家沉浸感&#xff0c;让其深度融入游戏&#xff0c;在操作角色或与环境互动时&#xff0c;通过触感反馈获得身临其境的真实感&#xff08;比如动作游戏中角色攻击或受击时的振动反馈&#xff0c;能使玩家更…

【OSS安全最佳实践】降低因账号密码泄露带来的未授权访问风险

如果因个人或者企业账号密码泄露引发了未经授权的访问&#xff0c;可能会出现非法用户对OSS资源进行违法操作&#xff0c;或者合法用户以未授权的方式对OSS资源进行各类操作&#xff0c;这将给数据安全带来极大的威胁。为此&#xff0c;OSS提供了在实施数据安全保护时需要考虑的…

6. Python 输出长方形,直角三角形,等腰三角形

使用Python输出长方形&#xff0c;直角三角形&#xff0c;等腰三角形 这里主要使用python语言里的循环知识&#xff0c;具体说是Python语言里的循环嵌套&#xff0c; 注意&#xff0c;在实际使用中&#xff0c;循环嵌套一般最多到达3层&#xff0c;嵌套太多会影响到程序执行。…