Java 手写设计HashMap源码,让面试官膜拜

Java 手写HashMap源码,让面试官膜拜

一,手写源码

这是一个模仿HashMap的put,get功能的自定义的MyHashMap

package cn.wxs.demo;import java.io.Serializable;
import java.util.*;
import java.util.function.BiConsumer;class MyHashMap<K, V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {private static final int DEFAULT_CAPACITY = 16;private static final float DEFAULT_LOAD_FACTOR = 0.75f;private Node<K, V>[] table; // 存储桶数组private transient int size; // 键值对数量private transient int modCount;  //总数private transient int threshold; // 扩容阈值private float loadFactor; // 负载因子@Overridepublic void forEach(BiConsumer<? super K, ? super V> action) {MyHashMap.Node<K,V>[] tab;if (action == null)throw new NullPointerException();if (size > 0 && (tab = table) != null) {int mc = modCount;for (int i = 0; i < tab.length; ++i) {for (MyHashMap.Node<K,V> e = tab[i]; e != null; e = e.next)action.accept(e.key, e.value);}if (modCount != mc)throw new ConcurrentModificationException();}}public MyHashMap() {this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR);}public MyHashMap(int initialCapacity, float loadFactor) {if (initialCapacity <= 0)throw new IllegalArgumentException("Invalid initial capacity");if (loadFactor <= 0 || Float.isNaN(loadFactor))throw new IllegalArgumentException("Invalid load factor");this.table = new Node[initialCapacity];this.size = 0;this.loadFactor = loadFactor;this.threshold = (int) (initialCapacity * loadFactor);}public V get(Object key) {Node<K, V> node = getNode((K) key);return (node != null) ? node.value : null;}public V put(K key, V value) {if (key == null)putForNullKey(value);elseputNonNullKey(key, value);return value;}@Overridepublic Set<Entry<K, V>> entrySet() {return null;}private void putNonNullKey(K key, V value) {int hash = hash(key);int index = indexFor(hash, table.length);// 遍历链表,查找是否已存在相同的键for (Node<K, V> node = table[index]; node != null; node = node.next) {if (node.hash == hash && Objects.equals(node.key, key)) {// 如果找到相同的键,更新对应的值node.value = value;return;}}// 如果没有找到相同的键,将新的键值对添加到链表头部addNode(hash, key, value, index);}private void putForNullKey(V value) {// 对于 null 键,存储在数组的第一个位置for (Node<K, V> node = table[0]; node != null; node = node.next) {if (node.key == null) {// 如果找到 null 键,更新对应的值node.value = value;return;}}// 如果没有找到 null 键,将新的键值对添加到链表头部addNode(0, null, value, 0);}private void addNode(int hash, K key, V value, int bucketIndex) {// 检查是否需要扩容if (size >= threshold)resize(2 * table.length);// 将新的节点添加到链表头部Node<K, V> newNode = new Node<>(hash, key, value, table[bucketIndex]);table[bucketIndex] = newNode;size++;modCount++;}private Node<K, V> getNode(K key) {if (key == null)return getNodeForNullKey();int hash = hash(key);int index = indexFor(hash, table.length);// 遍历链表,查找指定的键for (Node<K, V> node = table[index]; node != null; node = node.next) {if (node.hash == hash && Objects.equals(node.key, key))return node;}return null;}private Node<K, V> getNodeForNullKey() {// 对于 null 键,存储在数组的第一个位置for (Node<K, V> node = table[0]; node != null; node = node.next) {if (node.key == null)return node;}return null;}private int hash(K key) {// 计算键的哈希值return (key == null) ? 0 : key.hashCode();}private int indexFor(int hash, int length) {// 根据哈希值和数组长度计算索引位置return hash & (length - 1);}private void resize(int newCapacity) {Node<K, V>[] oldTable = table;int oldCapacity = oldTable.length;// 检查是否达到容量上限if (oldCapacity >= 1 << 30)threshold = Integer.MAX_VALUE;elsethreshold = (int) (newCapacity * loadFactor);// 创建新的数组,将旧的键值对重新分配到新的数组中Node<K, V>[] newTable = new Node[newCapacity];transfer(oldTable, newTable);table = newTable;}private void transfer(Node<K, V>[] src, Node<K, V>[] dest) {// 遍历旧的数组,将键值对重新分配到新的数组中for (Node<K, V> node : src) {while (node != null) {Node<K, V> next = node.next;int index = indexFor(node.hash, dest.length);node.next = dest[index];dest[index] = node;node = next;}}}static class Node<K, V> {final int hash; // 哈希值final K key; // 键V value; // 值Node<K, V> next; // 下一个节点Node(int hash, K key, V value, Node<K, V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}}public static void main(String[] args) {MyHashMap<String,String> param = new MyHashMap<>();param.put("你好","你好");param.put("你好1","你好1");param.put("你好2","你好2");param.put("你好3","你好3");param.put("你好4","你好4");param.put("你好5","你好4");param.put("你好6","你好4");param.put("你好7","你好4");param.put("你好8","你好4");param.put("你好9","你好4");param.put("你好10","你好4");param.put("你好11","你好4");param.put("你好12","你好4");param.put("你好13","你好4");param.put("你好14","你好4");param.put("你好15","你好4");param.put("你好16","你好4");param.put("你好17","你好4");param.put("你好18","你好4");param.put("你好20","你好4");param.put("你好21","你好4");param.put("你好22","你好4");param.put("你好23","你好4");param.put("你好24","你好4");param.put("你好25","你好4");param.put("你好26","你好4");param.put("你好27","你好4");param.put("你好28","你好4");param.put("你好29","你好4");param.put("你好30","你好4");param.put("你好31","你好4");param.put("你好32","你好4");param.forEach((k,v)-> System.out.println(k));
//        System.out.println(param.get("你好4"));}
}

在这里插入图片描述

二,代码介绍

1.这是一个简单的自定义哈希映射(HashMap)的实现。功能不太完善,代码不太优雅,细节不够好,没有源码的那么好。后面我会慢慢进行优化
2.这段代码实现了一个简化版本的 HashMap,包含了 put 和 get 方法,并使用了数组+链表的存储结构。注意,这里的红黑树部分并未实现,只使用了链表来处理冲突。由于短时间没有办法能按自己的方式写出来全部的功能和底层设计,难度还是比较大的后期我会慢慢的把存储结构改成数组+链表+红黑树的数据结构

请注意,这只是一个简化版本的实现,并没有处理扩容、红黑树转换等复杂的细节。实际的 HashMap 实现要复杂得多。如果你对完整的实现感兴趣,建议你查阅 Java 的 HashMap 源代码,以便更好地理解和学习。

三,下期完善功能

size()
remove(key)
containsKey(key)
containsValue(value)

三,HashMap

HashMap 是 Java 中的一个常用的数据结构,它实现了 Map 接口,并且基于哈希表实现。HashMap 允许存储键值对,并且提供了快速的插入、查找和删除操作。

下面是 HashMap 的一些重要特点和概念:

  • 哈希表HashMap 内部使用了一个数组来存储数据,这个数组被称为哈希表。哈希表的每个元素称为一个桶(bucket),每个桶可以存储一个或多个键值对。通过计算键的哈希值,可以确定键值对在哈希表中的位置。

  • 哈希函数:哈希函数用于将键映射到哈希表中的索引位置。好的哈希函数能够将键均匀地分布在哈希表的不同位置上,以减少冲突的概率。在 HashMap 中,键的 hashCode() 方法被用作哈希函数。

  • 冲突:当两个不同的键通过哈希函数计算得到的索引位置相同时,就发生了冲突。HashMap 使用链表或红黑树来解决冲突。当冲突较少时,使用链表;当链表长度超过一定阈值时,转换为红黑树,以提高查找的效率。

  • 键的唯一性:在 HashMap 中,键是唯一的。如果尝试将一个已经存在的键插入到 HashMap 中,它的值将被更新为新的值。

  • null 键HashMap 允许存储一个键为 null 的键值对。这个键将被存储在哈希表的第一个位置上。

  • 迭代顺序HashMap 不保证键值对的迭代顺序,它通常是不确定的。如果需要有序的键值对集合,可以使用 LinkedHashMap

下面是一些常用的操作方法:

  • put(key, value):向 HashMap 中插入一个键值对。
  • get(key):根据键获取对应的值。
  • remove(key):根据键删除对应的键值对。
  • containsKey(key):检查是否包含指定的键。
  • containsValue(value):检查是否包含指定的值。
  • size():返回 HashMap 中键值对的数量。

需要注意的是,HashMap 是非线程安全的,如果在多线程环境中使用,需要进行适当的同步处理,或者使用线程安全的 ConcurrentHashMap

HashMap 的时间复杂度通常是常数级别的,即 O(1),但在最坏的情况下,可能会达到 O(n),其中 n 是 HashMap 中存储的键值对数量。

希望这个简介对你理解 HashMap 有所帮助!如果你有任何其他问题,请随时提问。

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

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

相关文章

面向对象三大特征——封装

目录 1. 封装概述&#xff08;封装与隐藏&#xff09; 2. private关键字 3. Getter & Setter方法 4. 变量访问原则和this关键字 5. 构造方法 5.1 构造方法概述 5.2 构造方法和set方法的比较 6. 静态 6.1 静态概述 6.2 静态效果 6.3 静态变量和非静态变量的区别 …

win11 CUDA(12.3) + cuDNN(12.x) 卸载

win11 CUDA&#xff08;12.3&#xff09; cuDNN&#xff08;12.x&#xff09;卸载 信息介绍卸载 信息介绍 本文是对应 win11RTX4070Ti 安装 CUDA cuDNN&#xff08;图文教程&#xff09; 的卸载 卸载 控制面板 --> 程序 --> 卸载程序 卸载掉图中红框内的&#xff0c…

reinforce 跑 CartPole-v1

gym版本是0.26.1 CartPole-v1的详细信息&#xff0c;点链接里看就行了。 修改了下动手深度强化学习对应的代码。 然后这里 J ( θ ) J(\theta) J(θ)梯度上升更新的公式是用的不严谨的&#xff0c;这个和王树森书里讲的严谨公式有点区别。 代码 import gym import torch from …

Android 11 适配——整理总结篇

背景 > 经过检测&#xff0c;我们识别到您的应用&#xff0c;目前未适配安卓11&#xff08;API30&#xff09;&#xff0c;请您关注适配截止时间&#xff0c;尽快开展适配工作&#xff0c;避免影响应用正常发布和经营。 > targetSdkVersion30 升级适配工作参考文档&am…

从零开发短视频电商 Jmeter压测示例模板详解(无认证场景)

文章目录 添加线程组添加定时器添加HTTP请求默认值添加HTTP头管理添加HTTP请求添加结果断言响应断言 Response AssertionJSON断言 JSON Assertion持续时间断言 Duration Assertion 添加察看结果树添加聚合报告添加表格察看结果参考 以压测百度搜索为例 https://www.baidu.com/s…

class066 一维动态规划【算法】

class066 一维动态规划 算法讲解066【必备】从递归入手一维动态规划 code1 509斐波那契数列 // 斐波那契数 // 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 // 该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。…

kotlin - ViewBinding

前言 为什么用ViewBinding&#xff0c;而不用findViewById()&#xff0c;这个有很多优秀的博主都做了讲解&#xff0c;就不再列出了。 可参考下列博主的文章&#xff1a; kotlin ViewBinding的使用 文章里也给出了如何在gradle中做出相应的配置。 &#xff08;我建议先看这位博…

【LeetCode热题100】【滑动窗口】无重复字符的最长子串

给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。示例 2: 输入: s "bbbbb" 输出: 1 解释: 因为无…

Redis,什么是缓存穿透?怎么解决?

Redis&#xff0c;什么是缓存穿透&#xff1f;怎么解决&#xff1f; 1、缓存穿透 一般的缓存系统&#xff0c;都是按照key去缓存查询&#xff0c;如果不存在对用的value&#xff0c;就应该去后端系统查找&#xff08;比如DB数据库&#xff09;。一些恶意的请求会故意查询不存在…

不想写大量 if 判断?试试用规则执行器优化,就很丝滑!

近日在公司领到一个小需求&#xff0c;需要对之前已有的试用用户申请规则进行拓展。我们的场景大概如下所示: if (是否海外用户) {return false; }if (刷单用户) {return false; }if (未付费用户 && 不再服务时段) {return false }if (转介绍用户 || 付费用户 || 内推…

16ASM 分段和机器码

8086CPU存储分段管理 问题1&#xff1a;8086是16位cpu&#xff0c;最多可访问&#xff08;寻址&#xff09;多大内存&#xff1f; 运算器一次最多处理16位的数据。地址寄存器的最大宽度为16位。访问的最大内存为&#xff1a;216 64K 即 0000 - FFFF。 问题2&#xff1a;808…

WIFI直连(Wi-Fi P2P)

一、概述 Wifi peer-to-peer&#xff08;也称Wifi-Direct&#xff09;是Wifi联盟推出的一项基于原来WIfi技术的可以让设备与设备间直接连接的技术&#xff0c;使用户不需要借助局域网或者AP&#xff08;Access Point&#xff09;就可以进行一对一或一对多通信。这种技术的应用…

计算机毕业设计 SpringBoot的乐乐农产品销售系统 Javaweb项目 Java实战项目 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

Xmanager

什么是 XManager Xmanager 是市场上领先的 PC X 服务器&#xff0c;可将X应用程序的强大功能带入 Windows 环境。 提供了强大的会话管理控制台&#xff0c;易于使用的 X 应用程序启动器&#xff0c;X 服务器配置文件管理工具&#xff0c;SSH 模块和高性能 PC X 服务器。 Xman…

javaScript(六):DOM操作

文章目录 1、DOM介绍2、DOM&#xff1a;获取Element对象3、DOM&#xff1a;事件监听3.1、事件介绍3.2、常见事件3.3、设置事件的两种方式3.4、事件案例 1、DOM介绍 概念 Document Object Model &#xff0c;文档对象模型 将标记语言的各个组成部分封装为对应的对象&#xff1a…

Realme X7 Pro Root 刷机教程

Realme X7 Pro 刷机教程 Just For Fun&#xff0c;最近倒腾了下Realme X7 Pro 刷root。此博客为个人记录刷机过程&#xff0c;如有机友跟随本教程操作&#xff0c;请谨慎操作&#xff01;&#xff01;&#xff01; 以下教程真针对Realme X7 Pro&#xff0c;其他版本方法未知&…

【Flutter】vs2022上开发flutter

在vs上开发flutter&#xff0c;结果扩展仓库上没办法找到Dart&#xff0c;Flutter。 在 这 搜索Dart时也无法找到插件。 最后发现是安装工具出错了 安装了 开发需要的是

从线性回归到神经网络

目录 一、线性回归关键思想 1、线性模型 2、基础优化算法 二、线性回归的从零开始实现 1、生成数据集 2、读取数据集 3、初始化模型参数 4、定义模型 5、定义损失函数 6、定义优化算法 7、训练 三、线性回归的简洁实现 1、生成数据集 2、读取数据集 3、定义模型…

论文代码阅读:TGN模型训练阶段代码理解

文章目录 [toc] TGN模型训练阶段代码理解论文信息代码过程手绘代码训练过程compute_temporal_embeddingsupdate_memoryget_raw_messagesget_updated_memoryself.message_aggregator.aggregateself.memory_updater.get_updated_memoryMemoryget_embedding_moduleGraphAttentionE…

【AIGC】Midjourney高级进阶版

Midjourney 真是越玩越上头&#xff0c;真是给它的想象力跪了~ 研究了官方API&#xff0c;出一个进阶版教程 命令 旨在介绍Midjourney在Discord频道中的文本框中支持的指令。 1&#xff09;shorten 简化Prompt 该指令可以将输入的Prompt为模型可以理解的语言。模型理解语言…