【容器源码篇】Map容器(HashTable,HashMap,TreeMap的特点)

文章目录

  • ⭐容器继承关系
    • 🌹Map容器
      • 🗒️HashTable源码解析
        • 构造方法
        • put方法
        • remove方法
        • rehash扩容
      • 🗒️HashMap源码解析
        • 构造函数
        • get方法
        • put方法
          • 详解
        • 扩容方法
          • 详解
        • 🗒️TreeMap源码解析

在这里插入图片描述

⭐容器继承关系

在这里插入图片描述

🌹Map容器

键值对映射:Map容器中的元素是以键值对的形式存储的,每个键对应一个值。通过键可以快速查找对应的值。

键不重复:Map中的键是唯一的,每个键对应一个值。如果添加已经存在的键,则会更新对应的值。

常用操作:Map提供了添加键值对、获取值、判断是否包含某个键等基本操作。

遍历:可以通过键集、值集或者键值对集合来遍历Map中的元素。

🗒️HashTable源码解析

线程安全:Hashtable 是同步的,可以在多线程环境中安全地使用。这意味着多个线程可以同时读写 Hashtable 而不会出现并发问题。

不允许 null 键或值:Hashtable 不允许键或值为 null,如果尝试插入 null 键或值,会抛出 NullPointerException 异常。

初始容量和加载因子:Hashtable 有一个初始容量和加载因子,当哈希表中的元素数量超过加载因子乘以容量时,哈希表会自动扩容。

构造方法

在这里插入图片描述
默认容量是11,加载因子是0.75
在这里插入图片描述
指定装载容量,加载因子是0.75
在这里插入图片描述
如果用户传入的initialCapacity为0,将初始容量设为1,确保哈希表至少有一个桶用于存储元素。
计算哈希表的扩容阈值,其值为initialCapacity乘以loadFactor的结果与MAX_ARRAY_SIZE + 1之间的较小值。当哈希表中的元素数量超过这个阈值时,会触发扩容操作以保证哈希表的性能。
在这里插入图片描述

在函数内部,首先根据传入的map的大小计算出一个初始容量,并将其和11中的较大值作为Hashtable的容量,并设置加载因子为0.75。然后调用putAll方法将传入的map中的所有键值对复制到新创建的Hashtable中。

put方法

在这里插入图片描述

将指定的键(key)映射到指定的值(value),并将其添加到哈希表中。如果该键已经存在于哈希表中,则用新值替换旧值,并返回旧值。如果该键不存在,则将新键值对添加到哈希表中。该方法是同步的,可以避免多线程环境下的并发问题。需要注意的是,键和值都不能为null。
在这里插入图片描述

hash 是传入键对象(Key)的hashCode值。
0x7FFFFFFF 是一个32位的整数,其二进制表示为一串1,与操作符 “&” 用来获取 hash 的正向32位整数值,确保结果非负。
% tab.length 是对得到的无符号32位整数取模运算,目的是将哈希码映射到哈希表的实际索引位置上,这样即使哈希表大小不同也能保证键均匀分布。
整体来说,这段代码的作用是根据给定的键对象的hashCode值确定其在哈希表数组中的索引位置。

remove方法

在这里插入图片描述

rehash扩容

在这里插入图片描述
获取旧哈希表的容量和映射数组。
计算新哈希表的容量,当新容量超过最大数组大小时,将其设置为最大数组大小。
创建新哈希表映射数组。
更新哈希表的修改次数和阈值。
将旧哈希表中的每个键值对重新哈希到新哈希表中。

🗒️HashMap源码解析

非线程安全:HashMap 不是同步的,因此不适合在多线程环境中直接使用。如果需要在多线程环境中使用,可以通过 Collections.synchronizedMap 方法来创建一个线程安全的 Map。

允许 null 键和值:在 Java 8 之后,HashMap 允许 null 作为键和值。

初始容量和负载因子:HashMap 有一个初始容量和负载因子。当哈希表中的元素数量超过负载因子乘以容量时,哈希表会自动扩容。

构造函数

在这里插入图片描述
这一段代码和上面HashTable的构造函数很像

get方法

在这里插入图片描述
首先根据哈希值和表的长度计算出节点在表中的索引位置,然后获取该位置上的节点。如果该节点存在并且与 给定的键 相等,则返回该节点。如果该节点存在但是是一个TreeNode(红黑树节点),则将获取节点的操作委托给TreeNode的getTreeNode方法。如果该节点存在但是下一个节点不为空,则遍历下一个节点,重复上述判断操作,直到找到相等的节点或者遍历结束。如果在整个表中找不到相等的节点,则返回null。

put方法

在这里插入图片描述
在这里插入图片描述

详解

在这里插入图片描述
Node<K,V>[] tab中tab表示的就是数组。Node<K,V> p中p表示的就是当前插入的节点
在这里插入图片描述
如果数组是空的,那么就通过resize方法来创建一个新的数组
在这里插入图片描述
i表示在数组中插入的位置,计算的方式为(n - 1) & hash。在这里需要判断插入的位置是否是冲突的,如果不冲突就直接newNode,插入到数组中即可

如果冲突了,进入下面的分析

在这里插入图片描述

判断table[i]中的元素是否与插入的key一样,若相同那就直接使用插入的值p替换掉旧的值e。
在这里插入图片描述
判断插入的数据结构是红黑树还是链表,在这里表示如果是红黑树,那就直接putTreeVal到红黑树中

如果是链表,就进入下面的分析
在这里插入图片描述

如果数据结构是链表,首先要遍历table数组是否存在,如果不存在直接newNode(hash, key, value, null)。如果存在了直接使用新的value替换掉旧的。

注意一点:不存在并且在链表末尾插入元素的时候,会判断binCount >= TREEIFY_THRESHOLD - 1。也就是判断当前链表的长度是否大于阈值8,如果大于那就会把当前链表转变成红黑树,方法是treeifyBin
在这里插入图片描述
插入成功之后,还要判断一下实际存在的键值对数量size是否大于阈值threshold。如果大于那就开始扩容了。

扩容方法

在这里插入图片描述

详解

在这里插入图片描述
首先如果超过了数组的最大容量,那么就直接将阈值设置为整数最大值,然后如果没有超过,那就扩容为原来的2倍,这里要注意是oldThr << 1,移位操作来实现的。
在这里插入图片描述

第一个else if表示如果阈值已经初始化过了,那就直接使用旧的阈值。然后第二个else表示如果没有初始化,那就初始化一个新的数组容量和新的阈值。

🗒️TreeMap源码解析

有序性:TreeMap中的键值对根据键的自然顺序或自定义排序规则进行排序,因此可以按照键的顺序进行遍历。

红黑树:TreeMap内部使用红黑树作为数据结构,这种自平衡二叉搜索树能够保持键值对的有序性,并且提供了较快的插入、删除和查找操作。

键的唯一性:TreeMap中的键是唯一的,如果尝试插入一个已存在的键,则会覆盖原有的值。

性能:TreeMap提供了对数时间复杂度的插入、删除和查找操作,适合于需要有序存储和查找的场景。

导航方法:TreeMap提供了许多导航方法,如firstKey()、lastKey()、lowerKey(K key)、higherKey(K key)等,可以方便地进行范围查找和导航操作。

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

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

相关文章

少量的样本对于深度学习来说,会造成过拟合还是欠拟合呢?

少量样本通常会导致过拟合&#xff0c;而不是欠拟合。过拟合指模型在训练数据上表现良好&#xff0c;但在未见过的测试数据上表现不佳&#xff0c;因为模型过于复杂&#xff0c;试图捕获训练数据中的噪声和细微特征。由于训练数据有限&#xff0c;模型可能会过度适应这些数据的…

基本数据类型

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 数据类型是一种用于描述数据存储格式的结构。 PL/SQL 和其他编程语言一样也有多种数据类型&#xff0c;PL/SQL 语言中的常用数据类型和 Oracle 数据库中内置的数据类型基本…

动手学机器学习K近邻算法+习题

K近邻算法 import matplotlib.pyplot as plt import numpy as np import os# 读入mnist数据集 m_x np.loadtxt(mnist_x, delimiter ) m_y np.loadtxt(mnist_y)# 数据集可视化 data np.reshape(np.array(m_x[0], dtypeint), [28, 28]) plt.figure() plt.imshow(data, cmapgr…

(C++笔试题)选择题+编程题

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 选择题 第一道 下面对析构函数的正确描述是&#xff08;&#xff09; A. 系统不能提供默认的析构函数B. 析构函数必须由用户定义C. 析构函数没有参数D. 析构函数可以设置默认参数 解析&#xff1a; 正确描述析构函数的…

tab切换组件,可横向自适应滑动

示例图&#xff1a; 注&#xff1a;需要引入Jquery <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><style>.tabs-box {width: 100%;height: auto;}.tab-header-box {display: flex;overflow: hidden…

【AI】『Suno』哎呦不错呦,AI界的周董,快来创作你的歌曲吧!

前言 &#x1f34a;缘由 Suno AI的旋风终于还是吹到了音乐圈 &#x1f3c0;事情起因&#xff1a; 朋友说他练习时长两天半&#xff0c;用Suno发布了首张AI音乐专辑。震惊之余&#xff0c;第一反应是音乐圈门槛也这么低了&#xff0c;什么妖魔鬼怪都可以进军了嘛&#xff01;…

unity学习(77)--多玩家信息交互--不同类型的数据包

明白各个数据包的作用&#xff0c;以及是否正确的发挥作用 1.“120包”&#xff0c;客户端登录时发给服务器的&#xff0c;服务器处理后返回“121包”。 2.“121包” &#xff0c;服务器返回给客户端的&#xff0c;包含登录时所有在线玩家的信息。 客户端也通过createPlayer函…

【Android Studio3.5.2安装以及错误错误解决】

前言 下面是博主在安装Android studio时遇到的一些问题&#xff0c;并且花费很长时间寻找解决方法&#xff0c;经过了血和泪的教训下面将自己在安装过程中遇到的查看的资料贴出来&#xff08;感谢各位大佬的文章帮助本闲狗解答疑惑&#xff0c;此处贴出原文链接&#xff0c;如…

VTK 9.2.6 源码和VTK Examples 编译 Visual Studio 2022

对于编译 VTK 源码和编译详细的说明&#xff1a; VTK 源码编译&#xff1a; 下载源码&#xff1a; 从 VTK 官方网站或者 GitHub 获取源代码。官网目前最近的9.3.0有问题&#xff0c;见VTK 9.3.0 编译问题 Visual Studio 2022去gitlab上选择9.2.6分支进行clone CMake 配置&…

基于Unity+Vue3通信交互的WebGL项目发布实践

基于UnityVue3通信交互的WebGL项目发布实践 实践路线 基于UnityVue3通信交互的WebGL项目发布实践问题背景准备工作解决方案项目实践小目标搭建Unity测试项目 创建Vue3测试项目运行项目验证unity和vue通信功能总结与展望 问题背景 我们最近需要把unity开发的pc项目迁移到web端&…

Manjaro 安装全新 Linux 版微信,从此告别 Wine

目前已经基本上使用 Manjaro 来工作&#xff0c;而工作离不开微信作为日常的工作沟通工具。因为微信官方一直没有 Linux 版本的&#xff0c;所以之前都只能够使用 Wine 版本&#xff0c;然后踩了不少坑&#xff0c;但还算能勉强使用。 最近听说微信终于要发布 Linux 版本的&am…

[flink 实时流基础] flink组件栈以及任务执行与资源划分

文章目录 7. Flink组件栈1. 部署层&#xff08;1&#xff09;Local模式&#xff08;2&#xff09;Cluster模式&#xff08;3&#xff09;Cloud模式 2.运行时3.API层4. 上层工具 8. 任务执行与资源划分1. 再谈逻辑视图到物理执行图2. 任务、算子子任务与算子链3. Slot与计算资源…