【数据结构】哈希表详解,举例说明 java中的 HashMap、HashTable及其区别

news2024/9/30 11:31:40

一、哈希表(Hash Table)简介:

哈希表是一种数据结构,用于实现字典或映射等抽象数据类型。它通过把关键字映射到表中的一个位置来实现快速的数据检索。哈希表的基本思想是利用哈希函数将关键字映射到数组的索引位置上,从而实现常数时间的查找、插入和删除操作

二、哈希表的基本组成部分:

在这里插入图片描述

  • 哈希函数(Hash Function): 哈希函数负责将关键字映射到哈希表的索引位置。一个好的哈希函数应该能够将关键字均匀地分布到哈希表的各个位置上,减少冲突的概率。
  • 数组(Array): 哈希表的主要存储结构是一个数组,通过哈希函数计算的索引将关键字映射到数组的位置上。
  • 冲突处理(Collision Resolution): 冲突是指两个不同的关键字被哈希函数映射到了相同的位置上。常见的冲突处理方法包括链地址法和开放地址法。
  • 链地址法(Separate Chaining): 每个哈希表的位置上维护一个链表,冲突的关键字被放入相应位置的链表中。如上图所示,是一个链地址法实现的哈希表。
  • 开放地址法(Open Addressing):如果发生冲突,就尝试寻找下一个可用的位置。有多种开放地址法的实现方式,如线性探测、二次探测等。

三、Java 中的 HashMap:

在 Java 中,HashMap 是基于哈希表实现的键值对存储的数据结构。以下是 HashMap 的一些重要特性和实现细节:

  • 数据结构: HashMap 使用数组存储键值对,每个数组元素称为桶(bucket)。每个桶可以存储多个键值对。
  • 哈希函数: HashMap 使用键的哈希码来确定桶的位置。Java 中的 hashCode() 方法用于获取对象的哈希码。
  • 冲突处理: 当多个键的哈希码映射到相同的桶上时,HashMap 使用链地址法或者红黑树来解决冲突,即在桶中维护一个链表。
  • 负载因子和扩容: HashMap 有一个负载因子(load factor)的概念,当桶中的键值对数量达到负载因子与桶的容量的乘积时,触发扩容操作。默认负载因子为 0.75。负载因子的值增大,冲突率也随着增大,我们不能直接控制冲突率,可以通过影响负载因子来降低冲率,而控制负载因子,负载因子是哈希表的元素数量除哈希桶数量,我们认为哈希表要传入的数量是未知的,也可以看作无穷的,所以,通过不能降低减少哈希表元素的数量来降低负载因子的值,但我们可以通过增加哈希桶的值来降低负载因子的值,进而降低冲突率。
  • 迭代顺序: HashMap 的迭代顺序不是固定的,不同版本的 JDK 可能有不同的实现。在 Java 8 之前,HashMap 的迭代顺序是不确定的。在 Java 8 及以后,为了提高性能,引入了红黑树(RB-tree)来优化链表,影响了迭代顺序。
  • 线程安全: HashMap 不是线程安全的,如果多个线程同时操作 HashMap,可能会导致并发问题。可以考虑使用 Collections.synchronizedMap() 或者 ConcurrentHashMap 来实现线程安全。参考【数据类型】ConcurrentHashMap分段锁实现高并发 和【数据类型】Collections.synchronizedMap 多线程Map
// 示例代码
import java.util.HashMap;
import java.util.Map;

public class HashMapExample {
    public static void main(String[] args) {
        // 创建 HashMap 实例
        Map<String, Integer> hashMap = new HashMap<>();

        // 添加键值对
        hashMap.put("Alice", 25);
        hashMap.put("Bob", 30);
        hashMap.put("Charlie", 22);

        // 获取值
        int age = hashMap.get("Bob");
        System.out.println("Bob's age: " + age);

        // 遍历 HashMap
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
    }
}

上述代码展示了使用 HashMap 存储和访问键值对的基本操作。

四、java中的HashTable

HashTable也是利用哈希表算法原理,Hashtable底层也采用数组+链表的数据结构进行实现,当哈希冲突发生时,使用链表来解决冲突。与HashMap不同的是,Hashtable在JDK 8及以前没有使用红黑树解决哈希冲突,这导致了其效率相对较低。还有以下几处不同:

1、同步性:

  • HashTable: 是线程安全的,所有的方法都是同步的,即在单个方法调用时,HashTable 会对其进行锁定,以确保线程安全。这使得在并发环境下,HashTable 是安全的,但在性能上可能会受到影响。
  • HashMap: 不是线程安全的。在多线程环境下,如果没有外部同步措施,对 HashMap 进行并发修改可能导致不确定的结果。

2、空值处理:

  • HashTable: 不允许键或值为 null,如果试图存储 null 键或值,会抛出 NullPointerException。
  • HashMap: 允许键和值为 null。

3、继承关系:

  • Hashtable 继承自Dictionary类,Dictionary类是一个已经被废弃的类(见其源码中的注释)。父类都被废弃,自然而然也没人用它的子类Hashtable了。
  • HashMap 继承自AbstractMap类,是 Java Collections Framework 中的一部分。但二者都实现了Map接口。

4、性能:

  • 由于 HashTable 在所有方法上使用同步,它在性能上可能会受到影响,尤其在多线程环境下。
  • HashMap 不使用同步,因此在单线程环境或者不需要线程安全保证的场景下,性能可能更好。

在新的 Java 5+ 版本中,推荐使用 HashMap 或者 ConcurrentHashMap 而不是
HashTable,因为它们提供了更好的性能和更灵活的使用方式。

5、包含的contains方法不同

  • hashtable则保留了 contains 方法,效果同 containsValue ,还包括 containsValue 和 containsKey 方法。
  • HashMap是没有 contains 方法的,而包括 containsValue 和 containsKey 方法.

6、应用场景

根据上述的区别和特点,我们可以得出以下建议:

  • 如果线程安全的Map集合,并且不需要存储null键或null值,可以选择Hashtable
  • 如果需要高效、非线程安全的Map集合,并且需要存储null键或null值,可以选择HashMap
  • 如果需要高效、线程安全的Map集合,可以选择使用ConcurrentHashMap,也允许键、值为null

知识是一个环,来我的博客绕圈吧~ 持续更新中,后续更精彩!

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

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

相关文章

四款免费、易用的Docker漏洞扫描工具

本文向您介绍四种既可以扫描Docker镜像中的漏洞&#xff0c;又能够被轻松地集成到CI/CD中的四种免费实用工具。 基本原理 所有这些工具的工作原理都比较类似。它们使用的是如下两步流程&#xff1a; 生成软件物料清单(Software Bill of Materials&#xff0c;SBOM)。将SBOM与…

USB PHY for FPGA layout

https://blog.csdn.net/qq_41904778/article/details/123967670 ZYNQ7000内部没有USB PYH&#xff0c;我们通过USB 3320 PHY 芯片来连接FPGA 和外部的USB端口&#xff08;DP & DP-&#xff09;。USB 3320 PHY跟FPGA内部是t通过ULPI接口试下的&#xff0c;然后把数据转化为…

windows下编译报‘mutex‘ in namespace ‘std‘ does not name a type的解决方案

问题复述&#xff1a; windows下使用MinGW编译工程时&#xff0c;报如下错误&#xff1a; error: ‘mutex’ in namespace ‘std’ does not name a type error: ‘mutex’ is not a member of ‘std’ error: ‘mutex’ was not declared in this scope 问题分析&#xff…

C#,字符串匹配(模式搜索)Sunday算法的源代码

Sunday算法是Daniel M.Sunday于1990年提出的一种字符串模式匹配算法。 核心思想&#xff1a;在匹配过程中&#xff0c;模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较&#xff0c;它在发现不匹配时&#xff0c;算法能跳过尽可能多的字符以进行下一步的匹配&…

跨域原理和解决方案

前置知识 什么是跨域 主要是由于浏览器的同源策略引起的&#xff0c;同源策略是浏览器的安全机制&#xff0c;当 协议&#xff0c;域名&#xff0c;端口 三者有一个不同&#xff0c;浏览器就禁止访问资源。 比如&#xff1a;http://www.company.com:80 http://www.company.…

chatgpt的实用技巧四temperature 格式

四、temperature 格式 GPT3.5 temperature 的范围为&#xff1a;0-0.7&#xff1b; GPT4.0 temperature 的范围为&#xff1a;0-1&#xff1b; 当 temperature 为 0 时候&#xff0c;结果可稳定。 当 temperature 为 0.7/1 时候&#xff0c;结果发散具备创力。 数值越大&a…

【动态规划】24子数组系列_最长湍流子数组_C++

题目链接&#xff1a;最长湍流子数组 目录 题目解析&#xff1a; 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目解析&#xff1a; 题目让我们求返回 arr 的 最大湍流子数组的长度 由题可得&#xff1a; 如果比较符号在子数组中的…

使用 ClassFinal 对SpringBoot jar加密加固并进行机器绑定

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01;如果我的博客对你有帮助&#xff0c;欢迎进行评论✏️✏️、点赞&#x1f44d;&#x1f44d;、收藏⭐️⭐️&#…

告别繁琐配置!JVS低代码逻辑引擎让你轻松实现高效数据处理

在当今高度数字化的世界中&#xff0c;逻辑引擎作为数据处理和业务逻辑的核心组件&#xff0c;其重要性不言而喻。它不仅关乎企业数据的准确处理&#xff0c;还影响着业务决策的效率和准确性。为了确保逻辑引擎的正常运行和准确性&#xff0c;配置和测试环节显得尤为重要。 本…

【技术】MySQL数据读写分离怎么实现

、概念&#xff1a; MySQL数据读写分离是存储数据的一种服务架构执行select命令必须连接 slave角色服务器执行insert命令必须连接 maste角色服务器提供数据读写分离功能的中间件软件有&#xff1a; mysql-proxy maxscale mycat拓扑架构只支持一主一从或者一主多从架构 二、实…

Docker搭建MySQL主从数据库-亲测有效

1、测试环境概述 1、使用MySQL5.7.35版本 2、使用Centos7操作系统 3、使用Docker20版本 案例中描述了整个测试的详细过程 2、安装Docker 2.1、如果已经安装docker,可以先卸载 yum remove -y docker \ docker-client \ docker-client-latest \ docker-common \ docker-l…

Spring-BeanPostProcessor PostConstruct init InitializingBean 执行顺序

执行顺序探究 新建一个对象用于测试 Component public class Student implements InitializingBean {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name name;}public int getAge() {return age;}pu…

Red Hat Enterprise Linux 7.9 安装图解

引导和开始安装 选择倒计时结束前&#xff0c;通过键盘上下键选择下图框选项&#xff0c;启动图形化安装过程。 安装语言选择 这里要区分一下&#xff0c;当前选中的语言作为安装过程中安装器所使用的语言&#xff0c;这里我们选择中文简体。不过细心的同学可能发现&#xff0c…

Js-WebAPIs-事件流(三)

• 事件流与两个阶段说明 事件流指的是事件完整执行过程中的流动路径 说明&#xff1a;假设页面里有个div&#xff0c;当触发事件时&#xff0c;会经历两个阶段&#xff0c;分别是捕获阶段、冒泡阶段 简单来说&#xff1a;捕获阶段是 从父到子 冒泡阶段是从子到父 实际工作都是…

Debian系统写Mysql时中文出现乱码无法定入的问题解决方案

原因是操作系统可能精简安装&#xff0c;没有GBK字符集&#xff0c;只有UTF8在转换或使用的时候有问题。 使用locale -a查看系统支持的字符集。正常的比较全的字符集的操作系统如下&#xff1a; 有问题的操作系统字符集如下&#xff1a; 解决方案&#xff1a; 步骤1&#…

LiveNVR监控流媒体Onvif/RTSP功能-服务接收RTSP推流RTSPServer可以拉转配置到通道中视频直播

LiveNVR服务接收RTSP推流RTSPServer可以拉转配置到通道中视频直播 1、需求背景2、开启RTSP2.1、基础配置配置RTSP端口 3、获取RTSP推流地址3.1、RTSP推流地址格式3.3、RTSP推流地址示例 4、配置设备推流5、配置拉转RTSP5.1、直播流地址格式5.2、直播流地地址示例5.3、通道配置直…

滑雪挑战H5小游戏

欢迎来到程序小院 滑雪挑战 玩法&#xff1a;点击鼠标左键控制人物滑雪的方向&#xff0c;注意不同的弯道&#xff0c;滑雪过程中会有⭐️&#xff0c;看你会获得⭐️&#xff0c;快去滑雪吧^^。开始游戏https://www.ormcc.com/play/gameStart/254 html <canvas id"c…

文件系统和IO流

目录 ​文件系统和IO流 一:文件的认知 认识文件 树型结构组织和⽬录: 文件路径&#xff08;Path): 文件形式: 二:File的方法 File的概述: File的属性 File的构造方法 File常用的get系列方法 ⽰例一:观察get系列的特点和差异 File常用的增,删方法 示例二:普通文件…

基于振弦采集仪的地下工程振动监测技术研究

基于振弦采集仪的地下工程振动监测技术研究 地下工程振动监测技术是为了监测地下工程施工过程中产生的振动而进行的研究。振弦采集仪是一种常用的地下工程振动监测设备&#xff0c;它通过固定在地下工程附近的振弦仪来实时采集工程施工过程中产生的振动信号。 基于振弦采集仪的…

5.文本文件编辑命令

1.cat 用于查看纯文本文件&#xff08;内容较少的&#xff09; 加上-n参数&#xff0c;显示内容加行号 [rootlocalhost ~]# cat -n /etc/sysconfig/network-scripts/ifcfg-ens160 2.more 用于查看纯文本文件&#xff08;内容较多的&#xff09; 还可以使用空格键或回车 键…