手撕HashMap(二)
- 这里再补充几个手撕HashMap的方法
1、remove()
- remove 方法参数值应该是键值对的键的值,当传入键值对的键的时候,remove 方法会删除对应的键值对
- 需要利用我们自己先前创建的 hashcodeList 来实现,hashcodeList 存入了所有被使用的 hashcode 值,方便后续的操作
- 在 put() 中,当添加新的键值对时,就会调用
hashcodeList.add(hashcode);来存入添加的 hashcode 值 - hashcodeList:
/**
* 不需要遍历数组,大大减少了代码量,直接存入hashcode的值
* 用来记录被使用的hashcode,方便后续其他方法的操作
*/
List<Integer> hashcodeList = new ArrayList<>();
- remove() 方法的思路:
- 根据传入的 key 的值,遍历 hashmap
- 当 key 的值相同时,删除它,与此同时遍历 hashcodeList
- 当 hashcodeList 中存储的哈希值与 key 通过 hashcode(key) 方法后得到的哈希值相等时,删除这个 hashcodeList 值
- 代码:
/**
* 删除传入的key值所对应的键值对对象
*
* @param key 传入的key
*/
@Override
public void remove(K key) {
int hashcode = hashcode(key);
for (Entry<K, V> entry : mapArr[hashcode]
) {
//要把hashcodeList中的hashcode删除
hashcodeList.removeIf(integer -> hashcode(entry.getKey()) == integer);
//删除 mapArr
if (entry.getKey().equals(key)) {
mapArr[hashcode].remove();
}
}
}
2、clear()
- clear 方法调用之后,会清除 hashmap 中所有的关联或映射,即清除所有的 key、value
- 思路:
- hashcodeList 中存储的是使用过的哈希值,而 mapArr 的下标是对应的哈希值,存储的是对应的value值
- 遍历 hashcodeList,将里面的值一个个取出来并放到 mapArr 的下标,一一调用 remove 方法
/**
* 清除 HashMap 中的所有关联或者映射
*/
@Override
public void clear() {
for (int i = 0; i < hashcodeList.size(); i++) {
for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
) {
mapArr[hashcodeList.get(i)].remove();
//同时要把hashcodeList中的hashcode清除
hashcodeList.clear();
}
}
}
3、containsKey()
- 传入一个 key 的值,判断是否存在这个键所对应的键值对,存在则返回 true,不存在则返回 false
- 思路:
- 先生成传入 key 的对应的哈希值
- 判断下标为这个哈希值的数组是否为空,为空则直接返回 false
- 如果不为空,则遍历这个数组找到相同的 key 则返回 true,否则返回 false
- 会出现数组下标越界,如果出现,则说明不存在这个下标,自然也不存在这个哈希值,所以可以用 try、catch 环绕直接返回false
/**
* 判断是否存在key值所对应的映射,返回一个布尔值
*
* @param key 传入一个key的值
* @return 判断是否存在key值所对应的映射,返回一个布尔值
*/
@Override
public boolean containsKey(K key) {
int hashcode = hashcode(key);
try {
//如果发现没存过,直接返回false
if (null == mapArr[hashcode]) {
return false;
} else {
//如果遍历能查找到key,则返回true
//如果遍历不能找到,则返回null
for (Entry<K, V> entry : mapArr[hashcode]
) {
if (entry.getKey().equals(key)) {
return true;
}
}
}
} catch (ArrayIndexOutOfBoundsException e) {
//只要出现数组下标越界就说明没找到,直接返回false
return false;
}
return false;
}
4、keySet()
- 作用很简单,返回一个集合,集合包含了所有的 key 的值
- 注意:是 key 的值,而不是哈希值
- 思路:
- 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,所以直接返回 null
- 否则遍历 mapArr 数组,下标为 hashcodeList 存储的哈希值,用 getKey 取出 key
/**
* 获取HashMap的键的集合,以Set<K>保存
*
* @return 返回key的集合
*/
@Override
public Set<K> keySet() {
//若没有hashcode值,直接返回空
if (null == hashcodeList) {
return null;
} else {
Set<K> kSet = new HashSet<>();
for (int i = 0; i < hashcodeList.size(); i++) {
//遍历 mapArr
for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
) {
kSet.add(entry.getKey());
}
}
return kSet;
}
}
5、values()
- 与 keySet 类似,作用是返回一个集合,其中包含了所有的 value 值
- 思路:
- 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,自然也不存在 value,所以直接返回 null
- 否则遍历 mapArr 数组,下标为 hashcodeList 存储的哈希值,用 getValue 取出 value
/**
* 获取HashMap中value的集合
*
* @return 返回value集合
*/
@Override
public Collection<V> values() {
//如果没有hashcode值,则直接返回空
if (null == hashcodeList) {
return null;
} else {
//生成一个集合
Collection<V> vCollection = new ArrayList<>();
for (int i = 0; i < hashcodeList.size(); i++) {
//遍历 mapArr
for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
) {
vCollection.add(entry.getValue());
}
}
return vCollection;
}
}
6、entrySet()
- 返回一个集合,包含了所有的键值对及其映射关系
- 思路:
- 当 hashcodeList 为空时,说明没有哈希值,自然也不存在 key,自然也不存在 value,所以直接返回 null
- 否则遍历 mapArr 数组,下标为 hashcodeList 存的哈希值,直接调用 add 方法添加
/**
* 得到 HashMap 中各个键值对映射关系的集合
*
* @return 返回一个映射关系的集合
*/
@Override
public Set<Entry<K, V>> entrySet() {
//若没有hashcode值,直接返回空
if (null == hashcodeList) {
return null;
} else {
Set<Entry<K, V>> entrySet = new HashSet<>();
for (int i = 0; i < hashcodeList.size(); i++) {
//遍历 mapArr
for (Entry<K, V> entry : mapArr[hashcodeList.get(i)]
) {
entrySet.add(entry);
}
}
return entrySet;
}
}
7、size()
- size 方法就是返回一个 int 值,是 hashmap 的键值对的数量
- 思路:很简单,遍历 hashcodeList,存在一个哈希值就说明存在一对键值对,直接加一即可
/**
* 得到 HashMap 键值对的数量
*
* @return 一个int型整数
*/
@Override
public int size() {
int count = 0;
for (int i = 0; i < hashcodeList.size(); i++) {
count++;
}
return count;
}
手撕HashMap(二)的更多相关文章
- 手撕HashMap
前言: 平时工作的时候,用的最多的就是ArrayList和HashMap了,今天看了遍HashMap的源码,决定自己手写一遍HashMap. 一.创建MyHashMap接口 我们首先创建一 ...
- NN入门,手把手教你用Numpy手撕NN(一)
前言 这是一篇包含极少数学推导的NN入门文章 大概从今年4月份起就想着学一学NN,但是无奈平时时间不多,而且空闲时间都拿去做比赛或是看动漫去了,所以一拖再拖,直到这8月份才正式开始NN的学习. 这篇文 ...
- NN入门,手把手教你用Numpy手撕NN(2)
这是一篇包含较少数学推导的NN入门文章 上篇文章中简单介绍了如何手撕一个NN,但其中仍有可以改进的地方,将在这篇文章中进行完善. 误差反向传播 之前的NN计算梯度是利用数值微分法,虽容易实现,但是计算 ...
- NN入门,手把手教你用Numpy手撕NN(三)
NN入门,手把手教你用Numpy手撕NN(3) 这是一篇包含极少数学的CNN入门文章 上篇文章中简单介绍了NN的反向传播,并利用反向传播实现了一个简单的NN,在这篇文章中将介绍一下CNN. CNN C ...
- 手撕代码:统计1到n二进制数中1出现的总次数
题目描述: 互娱手撕代码题. 统计从1到n这n个数的二进制表示中1出现的次数. 思路分析: 思路一:直接的做法是从1遍历到n,对于每个数和1做与操作,之后,对于这个数不断做右移操作,不断和1做与操作, ...
- 编译原理--05 用C++手撕PL/0
前言 目录 01 文法和语言.词法分析复习 02 自顶向下.自底向上的LR分析复习 03 语法制导翻译和中间代码生成复习 04 符号表.运行时存储组织和代码优化复习 05 用C++手撕PL/0 在之前 ...
- 手写HashMap,快手面试官直呼内行!
手写HashMap?这么狠,面试都卷到这种程度了? 第一次见到这个面试题,是在某个不方便透露姓名的Offer收割机大佬的文章: 这--我当时就麻了,我们都知道HashMap的数据结构是数组+链表+红黑 ...
- paip.简化字-手写参考二简字..共98个
paip.简化字-手写参考二简字..共98个 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/a ...
- Netty实现高性能IOT服务器(Groza)之手撕MQTT协议篇上
前言 诞生及优势 MQTT由Andy Stanford-Clark(IBM)和Arlen Nipper(Eurotech,现为Cirrus Link)于1999年开发,用于监测穿越沙漠的石油管道.目标 ...
- 手撕RPC框架
手撕RPC 使用Netty+Zookeeper+Spring实现简易的RPC框架.阅读本文需要有一些Netty使用基础. 服务信息在网络传输,需要讲服务类进行序列化,服务端使用Spring作为容器.服 ...
随机推荐
- CentOS 9 开局配置
CentOS 9 开局配置 CentOS 9 发布有几年了,一直没有尝试使用,CentOS 9 有一些变动. 查看系统基础信息 # 查看系统基础信息 [root@chenby ~]# neofetch ...
- stm32串口烧录程序
Step1:将BOOT0设置为1,BOOT1设置为0,mcuisp软件不使用STR和DTR烧录 Step2:程序下载完成后,再将BOOT0手动跳帽接GND,复位,这样STM32才可以从Flash中启动 ...
- 【Vue项目】尚品汇(五)Detail组件开发 实现轮播图和放大镜效果
1 基本准备工作 1.1 组件路由及数据准备 编写请求接口 api/index.js export const reqGetDetailInfo = (skuId ={}) => { retur ...
- C# 闭包类对弱引用的坑
闭包.弱引用的简单概念,大佬们描述的很多,有不了解的可以看看: 理解C#中的闭包 - 黑洞视界 - 博客园 (cnblogs.com) C#弱引用(WeakReference) - 简书 (jians ...
- Selenium 元素定位方式封装的实际应用
一.定位方式 二.实际应用 1.项目结构 2.locator_base.py 文件 # -*- coding: utf-8 -*- from selenium.webdriver.common.by ...
- NC17383 A Simple Problem with Integers
题目链接 题目 题目描述 You have N integers A1, A2, ... , AN. You are asked to write a program to receive and e ...
- abp(net core)+easyui+efcore实现仓储管理系统——供应商管理升级之上(六十三)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统--ABP总体介绍(一) abp(net core)+ ...
- PHP前后端交互
PHP是现如今十分流行的轻量级语言,经常用来做应用的后端开发,其特点是语法简单,十分容易上手.除了单独做后端,PHP还能够将程序嵌入到HTML文件中执行,非常容易实现简单的前后端交互.而且PHP的运行 ...
- 2022-09-02:以下go语言代码输出什么?A:9;B:11;C:编译错误;D:不确定。
2022-09-02:以下go语言代码输出什么?A:9:B:11:C:编译错误:D:不确定. package main import ( "fmt" ) func main() { ...
- 2020-10-23:go中channel的创建流程是什么?
福哥答案2020-10-23:1.元素大小是否小于2的16次方,否则throw.2.对齐检查,否则throw.3.元素大小和容量的乘积不能超出范围,否则panic.4.生成*hchan,设置buf.4 ...