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

一、哈希表(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

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

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

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

相关文章

EDA-数据探索-pandas自带可视化-iris

# 加载yellowbrick数据集 import os import pandas as pd FIXTURES os.path.join(os.getcwd(), "data") df pd.read_csv(os.path.join(FIXTURES,"iris.csv")) df.head()sepal_lengthsepal_widthpetal_lengthpetal_widthspecies05.13.51.40.2setosa14.93…

二.几何基础_直线

O以下皆为公理推导的定理,有公理组成的新的定义 一.角 1.由线所组成的新的定义 角: 一点出发由两个不同方向的射线组成的图像(注:构成角的边是无界线的) 顶点: 两射线交汇处,如图 可称顶点为 ∠ A 或 ∠ C A B , ∠ B A C ∠A或∠CAB,∠BAC ∠A或∠CAB,∠BAC边: 构成角的射…

Spring WebSocket实现实时通信的详细教程

简介 WebSocket 是基于TCP/IP协议&#xff0c;独立于HTTP协议的通信协议。WebSocket 连接允许客户端和服务器之间的全双工通信&#xff0c;以便任何一方都可以通过已建立的连接将数据推送到另一方。 我们常用的HTTP是客户端通过「请求-响应」的方式与服务器建立通信的&#x…

电力市场知识及市场出清电价(market clearing price)程序分享!

​Main-导览 一、电力市场概述 2000以前&#xff0c;国内并不存在电力市场&#xff0c;而是叫计划电力经济。发电侧为卖方&#xff0c;核算发电成本和利润上报国家&#xff0c;审核通过后就是上网电价。用户侧为买方&#xff0c;被动执行国家制定的分时电价。计划电力经济的优…

奇异值分解(SVD)【详细推导证明】

机器学习笔记 机器学习系列笔记&#xff0c;主要参考李航的《机器学习方法》&#xff0c;见参考资料。 第一章 机器学习简介 第二章 感知机 第三章 支持向量机 第四章 朴素贝叶斯分类器 第五章 Logistic回归 第六章 线性回归和岭回归 第七章 多层感知机与反向传播【Python实例…

使用opencv把视频转换为灰色并且逐帧率转换为图片

功能介绍 使用opencv库把视频转换为灰色&#xff0c;并且逐帧率保存为图片到本地 启动结果 整体代码 import cv2 import osvc cv2.VideoCapture(test.mp4)if vc.isOpened():open, frame vc.read() else:open Falseos.makedirs("grayAll", exist_okTrue) i 0 wh…

【Docker】Linux中使用Docker安装Nginx部署前后端分离项目应用

目录 一、概述 1. Nginx介绍 2. Nginx优势 3. Nginx的工作原理 二、容器创建 1. Mysql容器 2. Tomcat容器 3. Nginx容器 每篇一获 一、概述 1. Nginx介绍 Nginx&#xff08;发音为 "engine x"&#xff09;是一个开源的、高性能的 HTTP 服务器和反向代理服务…

项目开发中安全问题以及解决办法——客户请求需要校验

Slf4j RequestMapping("trustclientdata") Controller public class TrustClientDataController {//所有支持的国家private HashMap<Integer, Country> allCountries new HashMap<>();public TrustClientDataController() {allCountries.put(1, new Cou…

【音视频】基于NGINX如何播放rtmp视频流

背景 现阶段直播越来越流行&#xff0c;直播技术发展也越来越快。Webrtc、rtmp、rtsp是比较火热的技术&#xff0c;而且应用也比较广泛。本文通过实践来展开介绍关于rtmp如何播放。 概要 本文重点介绍基于NGINX如何播放rtmp视频流 正文 1、构造rtsp视频流 可以参考上一篇…

开发「定位线上问题」小工具总结

文章目录 1. 写在最前面1.1 背景1.2 思路 2. 如何快速解决问题2.1 分析问题2.2 补救问题2.2.1 思路2.2.2 实现 3. 碎碎念 1. 写在最前面 1.1 背景 同事给处理各种线上问题以及处理紧急要交付的需求版本的我&#xff0c;紧急插入了一个线上的问题&#xff1a; 问题说明&#…

甜蜜而简洁——深入了解Pytest插件pytest-sugar

在日常的软件开发中,测试是确保代码质量的关键步骤之一。然而,对于测试报告的生成和测试结果的可读性,一直以来都是开发者关注的焦点。Pytest插件 pytest-sugar 以其清晰而美观的输出,为我们提供了一种愉悦的测试体验。本文将深入介绍 pytest-sugar 插件的基本用法和实际案…

界面设计与品牌一致性

活动是电子商务行业最常见的运营手段之一&#xff0c;将借助各种节日不断推出促销活动&#xff1b;例如&#xff0c;从1月的元旦到12月的圣诞节&#xff0c;让用户关注节日的仪式&#xff0c;通过各种折扣促进用户订单&#xff0c;提高订单率。 让我们来思考一下活动页面是如何…

C++设计模式(李建忠)笔记4(完结)

C设计模式&#xff08;李建忠&#xff09; 本文是学习笔记&#xff0c;如有侵权&#xff0c;请联系删除。 参考链接 Youtube: C设计模式 Gtihub源码与PPT&#xff1a;https://github.com/ZachL1/Bilibili-plus 豆瓣: 设计模式–可复用面向对象软件的基础 总结23种设计模式…

Pymol快速做出Surface-cartoon图详细步骤

在使用Pymol时&#xff0c;每当想对某个部分进行单独操作时&#xff0c;可以通过选中以后&#xff0c;复制该对象并重命名的方式。例如以2j1x.pdb为例&#xff0c;原始导入文件后如下&#xff1a; 移除溶剂 PyMOL>remove solvent 对象选择 右下方的selecting表示选择的类…

Linux--进程控制

进程终止 进程终止是指一个正在运行的进程结束其执行并释放占用的系统资源的过程。进程可以通过以下几种方式终止&#xff1a; 正常终止&#xff1a;进程完成了它的任务&#xff0c;或者遇到了终止条件&#xff0c;例如调用了exit()函数或主函数执行完毕。 异常终止&#xff1…

Opencv小项目——手势数字刷TIKTOK

​ 写在前面&#xff1a; 很久没更新了&#xff0c;之前的实习的记录也算是烂尾了&#xff0c;但是好在自己的实习记录还是有的&#xff0c;最近也忙碌了很多&#xff0c;终于放假了&#xff0c;今天下午正好没事&#xff0c;闲来无事就随便做个小玩意吧。 思来想去&#xff…

Docker registry镜像仓库,私有仓库及harbor管理详解

目录 registry镜像仓库概述 Docker 镜像仓库&#xff08;Docker Registry&#xff09;&#xff1a; registry 容器&#xff1a; 私有仓库概述 搭建本地私有仓库示例 Harbor概述 harbor架构 详解构成 Harbor由容器构成 Harbor部署示例 环境准备 部署Docker-Compose服…

多路开关状态指示

1&#xff0e;  实验任务 AT89S51单片机的P1.0&#xff0d;P1.3接四个发光二极管L1&#xff0d;L4&#xff0c;P1.4&#xff0d;P1.7接了四个开关K1&#xff0d;K4&#xff0c;编程将开关的状态反映到发光二极管上。&#xff08;开关闭合&#xff0c;对应的灯亮&#xff0c;开…

Docker安装Nginx并部署MySQL容器构建

一.MySQL容器的构建 1.创建MySQL根目录及配置文件夹&data文件夹 mkdir -p mysql/{conf,data} 2.上传配置文件 将配置文件上传到conf文件夹&#xff08;数据库配置文件已放到置顶资源中&#xff09; 3.命令构建MySQL容器 /soft/mysql/conf/my.cnf:/etc/my.cnf目录为我们…

electron+vite+vue3 快速入门教程

文章目录 前言一、electron是什么&#xff1f;二、electron 进程模型1.主进程2.渲染进程3.预加载脚本4.进程通信4.1 sendon&#xff08;单向&#xff09;4.2 invokehandle (双向)4.3 主进程向渲染进程发送事件 三、窗口创建与应用事件四、技术栈和构建工具五、electron-vite安装…