HashMap系列-resize

news2025/2/25 17:32:11

1.resize 

public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    
    final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length; //老的数组容量
        int oldThr = threshold;//老的阈值
        int newCap, newThr = 0;
        if (oldCap > 0) {//老的数组容量大于0,说明table初始化过了
            if (oldCap >= MAXIMUM_CAPACITY) { //已经达到最大容量
                threshold = Integer.MAX_VALUE;
                return oldTab;
            } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY){//新容量=老容量*2
                newThr = oldThr << 1; // double threshold
            }
        } else if (oldThr > 0){ // initial capacity was placed in threshold
            newCap = oldThr;//这里是大于初始化容量的最小的2的n次方
        } else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;//默认为16
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); //16*0.75
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;//赋值新阈值
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr; //更新全局threshold
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];//根据新容量创建新数组
        table = newTab;//更新全局table
        if (oldTab != null) {//说明老数组有数据,需要分配到新数组
            for (int j = 0; j < oldCap; ++j) {//遍历数组
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {//第j个桶
                    oldTab[j] = null;//老数组的值赋值为null,方便回收
                    if (e.next == null){
                        //只有一个元素,新算出index,赋值给新数组newTab[index]
                        newTab[e.hash & (newCap - 1)] = e;
                    } else if (e instanceof TreeNode){//如果是树
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    } else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {//满足这个条件的元素组成一个链表
                                if (loTail == null){
                                    loHead = e;
                                } else{
                                    loTail.next = e;
                                }
                                loTail = e;
                            } else {//满足这个条件的元素组成一个链表
                                if (hiTail == null){
                                    hiHead = e;
                                } else{
                                    hiTail.next = e;
                                }
                                hiTail = e;
                            }
                        } while ((e = next) != null);

                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;//链表头
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;//链表头
                        }
                    }
                }
            }
        }
        return newTab;
    }
}

2.流程图

3.(e.hash & oldCap) == 0的理解

&:按位与 两个数都为1的时候,才为1

(e.hash & oldCap) == 0  新索引:j(跟老索引一致)

(e.hash & oldCap) != 0  新索引:j + oldCap

3.1. (e.hash & oldCap) == 0

假设oldCap是16,二进制就是 0001 0000

(e.hash & oldCap) == 0 的时候,e.hash的从右到左第5位为0:xxx0 xxxx

oldIndex = e.hash & (oldCap -1)   

xxx0  xxxx

0000 1111         15

===========

0000 xxxx

newIndex = e.hash & (2*oldCap - 1)

xxx0  xxxx

0001 1111           31

===========

0000  xxxx

所以,如果(e.hash & oldCap) == 0的时候,这些元素的新索引跟老索引一致。

3.2. (e.hash & oldCap) != 0

假设oldCap是16,二进制就是 0001 0000

(e.hash & oldCap) != 0 的时候,e.hash的从右到左第5位为1:xxx1 xxxx

oldIndex = e.hash & (oldCap -1)   

xxx1  xxxx

0000 1111         15

===========

0000 xxxx

newIndex = e.hash & (2*oldCap - 1)

xxx1  xxxx

0001 1111           31

===========

0001  xxxx

所以,如果(e.hash & oldCap) != 0的时候,这些元素的新索引=老索引+oldCap。

4.疑惑

在挪动老的数据到新table的时候,为啥要这样计算呢?这样计算并没有省什么时间吧

计算在新table的位置e.hash & (newCap - 1),这个跟e.hash & oldCap执行速度一样,为啥不直接用e.hash & (newCap - 1)计算?


if ((e.hash & oldCap) == 0) {//满足这个条件的元素组成一个链表
    if (loTail == null){
        loHead = e;
    } else{
        loTail.next = e;
    }
    loTail = e;
} else {//满足这个条件的元素组成一个链表
    if (hiTail == null){
        hiHead = e;
    } else{
        hiTail.next = e;
    }
    hiTail = e;
}

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

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

相关文章

【开源】基于Vue+SpringBoot的快乐贩卖馆管理系统

项目编号&#xff1a; S 064 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S064&#xff0c;文末获取源码。} 项目编号&#xff1a;S064&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 搞笑视频模块2.3 视…

用 PHP和html做一个简单的注册页面

用 PHP和html做一个简单的注册页面 index.html的设计 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title…

手眼标定 - 最终精度和误差优化心得

手眼标定 - 标定误差优化项 一、TCP标定误差优化1、注意标定针摆放范围2、TCP标定时的点次态与工作姿态尽可能保持相近 二、深度相机对齐矩阵误差1、手动计算对齐矩阵 三、拍照姿态1、TCP标定姿态优先2、水平放置棋盘格优先 为减少最终手眼标定的误差&#xff0c;可做或注意以下…

华为数通---配置Smart Link负载分担案例

定义 Smart Link&#xff0c;又叫做备份链路。一个Smart Link由两个接口组成&#xff0c;其中一个接口作为另一个的备份。Smart Link常用于双上行组网&#xff0c;提供可靠高效的备份和快速的切换机制。 目的 下游设备连接到上游设备&#xff0c;当使用单上行方式时&#x…

【dig命令查询方法】

dig&#xff08;Domain Information Groper&#xff09;是一个用于查询DNS&#xff08;域名系统&#xff09;的命令行工具&#xff0c;它可以帮助您获取关于域名的各种信息&#xff0c;如IP地址、MX记录、NS记录等。下面是dig的详细使用教程。 基本语法&#xff1a; dig [ser…

【华为数据之道学习笔记】3-4主数据治理

主数据是参与业务事件的主体或资源&#xff0c;是具有高业务价值的、跨流程和跨系统重复使用的数据。主数据与基础数据有一定的相似性&#xff0c;都是在业务事件发生之前预先定义&#xff1b;但又与基础数据不同&#xff0c;主数据的取值不受限于预先定义的数据范围&#xff0…

http和https的区别有哪些?

HTTP&#xff08;超文本传输协议&#xff09;和HTTPS&#xff08;HTTP Secure&#xff09;是互联网上用于数据传输的两种协议。它们的主要区别在于HTTPS提供了加密的传输机制&#xff0c;以提高数据在传输过程中的安全性。以下是HTTP和HTTPS的一些主要区别&#xff1a; 加密&a…

[linux运维] 利用zabbix监控linux高危命令并发送告警(基于Zabbix 6)

之前写过一篇是基于zabbix 5.4的实现文章&#xff0c;但是不太详细&#xff0c;最近已经有两个小伙伴在zabbix 6上操作&#xff0c;发现触发器没有str函数&#xff0c;所以更新一下本文&#xff0c;基于zabbix 6 0x01 来看看效果 高危指令出发问题告警&#xff1a; 发出邮件告…

如何将idea中导入的文件夹中的项目识别为maven项目

问题描述 大家经常遇到导入某个文件夹的时候&#xff0c;需要将某个子文件夹识别为maven项目 解决方案

【教程】逻辑回归怎么做多分类

目录 一、逻辑回归模型介绍 1.1 逻辑回归模型简介 1.2 逻辑回归二分类模型 1.3 逻辑回归多分类模型 二、如何实现逻辑回归二分类 2.1 逻辑回归二分类例子 2.2 逻辑回归二分类实现代码 三、如何实现一个逻辑回归多分类 3.1 逻辑回归多分类问题 3.1 逻辑回归多分类的代…

RabbitMQ-学习笔记(初识 RabbitMQ)

本篇文章学习于 bilibili黑马 的视频 (狗头保命) 同步通讯 & 异步通讯 (RabbitMQ 的前置知识) 同步通讯&#xff1a;类似打电话&#xff0c;只有对方接受了你发起的请求,双方才能进行通讯, 同一时刻你只能跟一个人打视频电话。异步通讯&#xff1a;类似发信息&#xff0c…

Hadoop3.x完全分布式环境搭建Zookeeper和Hbase

先在主节点上进行安装和配置&#xff0c;随后分发到各个从节点上。 1. 安装zookeeper 1.1 解压zookeeper并添加环境变量 1&#xff09;解压zookeeper到/usr/local文件夹下 tar -zxvf /usr/local2&#xff09;进入/usr/local文件夹将apache-zookeeper-3.8.0-bin改名为zookeep…

玩转Sass:掌握数据类型!

当我们在进行前端开发的时候&#xff0c;有时候需要使用一些不同的数据类型来处理样式&#xff0c;Sass 提供的这些数据类型可以帮助我们更高效地进行样式开发&#xff0c;本篇文章将为您详细介绍 Sass 中的数据类型。 布尔类型 在 Sass 中&#xff0c;布尔数据类型可以表示逻…

如何将微服务注册到nacos服务上

首先可在maven的父工程的pom文件中添加maven的dependencyManagement标签&#xff0c;引入spring-cloud-alibaba-dependencies坐标 <properties><spring.cloud.alibaba.version>2.2.9.RELEASE</spring.cloud.alibaba.version></properties><!-- 管理…

IntelliJ IDEA 2023.3 最新变化

关键亮点 AI Assistant 预览阶段结束 全面推出 Ultimate JetBrains AI Assistant 现已全面推出&#xff0c;搭载大量新功能和改进&#xff0c;助力提高您在 JetBrains IDE 中的工作效率。 最新更新包括编辑器中增强的直接代码生成、无需复制代码即可回答项目相关查询的上下文…

Spring Boot的日志

打印日志 打印日志的步骤: • 在程序中得到日志对象. • 使用日志对象输出要打印的内容 在程序中得到日志对象 在程序中获取日志对象需要使用日志工厂LoggerFactory,代码如下: package com.example.demo;import org.slf4j.Logger; import org.slf4j.LoggerFactory;public c…

[VSCode] Java开发环境配置

文章目录 1 VSCode & Java 安装1.1 安装 VSCode1.2 安装 JDK 2 环境变量配置3 在 VSCode 中安装 Java 扩展4 运行测试 1 VSCode & Java 安装 1.1 安装 VSCode Visual Studio Code 官方下载 地址&#xff1a; https://code.visualstudio.com/详细安装步骤这里不做赘…

408——知识点大杂烩

在完成专业课的一轮复习以及历年真题的学习后&#xff0c;发现选择题甚至个别大题的考点就单纯考对概念的理解&#xff0c;会就是会&#xff0c;不会想到脑壳疼都做不出来&#xff0c;而408的知识点主打一个多杂&#xff0c;所以过来整理一下笔记。本文的知识点主要是在我做题过…

【扩散模型】ControlNet从原理到实战

ControlNet从原理到实战 ControlNet原理ControlNet应用于大型预训练扩散模型ControlNet训练过程ControlNet示例1 ControlNet与Canny Edge2. ControlNet与Depth3. ControlNet与M-LSD Lines4. ControlNet与HED Boundary ControlNet实战Canny Edge实战Open Pose 小结参考资料 Cont…