HashMap原理及简单实现
public class MyHashMap<K, V> {
private class Entry<K, V> {
int hash;
K key;
V value;
Entry<K, V> next; Entry(int hash, K key, V value, Entry<K, V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
} private static final int DEFAULT_CAPACITY = 1 << 2; private Entry<K, V>[] table; private int capacity; private int size; private final float loadFactor = 0.75f; public MyHashMap() {
this(DEFAULT_CAPACITY);
} @SuppressWarnings("unchecked")
public MyHashMap(int capacity) {
if (capacity < 0) {
throw new IllegalArgumentException();
} else {
table = new Entry[capacity];
size = 0;
this.capacity = capacity;
}
} public int size() {
return size;
} public boolean isEmpty() {
return size == 0 ? true : false;
} public V put(K key, V value) {
if (key == null) {
throw new RuntimeException("key不可以为空!");
}
if (size >= capacity * loadFactor) {
// 开始rehash
resize(2 * table.length);
int hash = (null != key) ? hash(key) : 0;
int index = indexFor(hash, table.length);// 注意此时的table已经扩容了
}
V newValue = putEntry(key, value);
return newValue;
} @SuppressWarnings({ "rawtypes", "unchecked" })
private void resize(int newCapacity) {
System.out.println("我们要扩容了!!当前的size是:" + size);
// 让数组长度乘以两倍
Entry[] newTable = new Entry[newCapacity];
transfer(newTable, true);
table = newTable;
} @SuppressWarnings({ "rawtypes", "unchecked" })
private void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K, V> e : table) {
while (e != null) {
if (rehash) {
// 要重新hash
e.hash = null == e.key ? 0 : hash(e.key);
}
int index = indexFor(e.hash, newCapacity);
// 开始把e放进新的数组中
// 注意,每次插入新的值都必须要插在散列链表的头部
e.next = newTable[index];
newTable[index] = e;
e = e.next;
}
}
} private V putEntry(K key, V value) {
if (key == null) {
throw new RuntimeException("key不可以为空!");
}
int hash = hash(key);
int i = indexFor(hash, table.length);
Entry<K, V> newEn = new Entry<K, V>(hash, key, value, null);
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
// 代表当前的e和要添加的key冲突了,那么就覆盖
V oldValue = e.value;
e.value = value;// 当前的e的value要替换为新的value
return oldValue;
}
}
// 如果上面没有找到的话,就要往链表添加元素了
size++;
addEntry(newEn, i);
return value;
} private void addEntry(Entry<K, V> entry, int index) {
Entry<K, V> e = table[index];
table[index] = entry;
entry.next = e;
} public V get(K key) {
if (key == null) {
throw new RuntimeException("key不可以为空!");
}
Entry<K, V> entry = getEntry(key);
return null == entry ? null : entry.value;
} private Entry<K, V> getEntry(K key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
for (Entry<K, V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
return e;
}
}
return null;
} public V remove(K key) {
Entry<K, V> e = removeEntryForKey(key);
return (e == null ? null : e.value);
} private Entry<K, V> removeEntryForKey(K key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
int i = indexFor(hash, table.length);
Entry<K, V> cur = table[i];
Entry<K, V> e = cur;
while (e != null) {
if (e.hash == hash && (e.key == key || key.equals(e.key))) {
size--;
// 如果删除的是prev的话
if (cur == e) {
table[i] = e.next;
} else {
// 就让cur的next等于e的next
cur.next = e.next;
}
return e;
}
cur = e;
e = e.next;
}
return null;
} private int indexFor(int hash, int length) {
return hash & (length - 1);// 哈希值和长度减一做与运算
} private int hash(K key) {
return key.hashCode();
} public static void main(String[] args) {
MyHashMap<Integer, String> map = new MyHashMap<>();
}
}
HashMap原理及简单实现的更多相关文章
- Java 7 和 Java 8 中的 HashMap原理解析
HashMap 可能是面试的时候必问的题目了,面试官为什么都偏爱拿这个问应聘者?因为 HashMap 它的设计结构和原理比较有意思,它既可以考初学者对 Java 集合的了解又可以深度的发现应聘者的数据 ...
- Java注解的基本概念和原理及其简单实用
一.注解的基本概念和原理及其简单实用 注解(Annotation)提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析 ...
- HashMap原理(二) 扩容机制及存取原理
我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor ...
- HashSet的实现原理,简单易懂
HashSet的实现原理,简单易懂 答: HashSet实际上是一个HashMap实例,都是一个存放链表的数组.它不保证存储元素的迭代顺序:此类允许使用null元素.HashSet中不允许有重复元 ...
- Java 实现《编译原理》简单-语法分析功能-LL(1)文法 - 程序解析
Java 实现<编译原理>简单-语法分析功能-LL(1)文法 - 程序解析 编译原理学习,语法分析程序设计 (一)要求及功能 已知 LL(1) 文法为: G'[E]: E→TE' E'→+ ...
- java中HashMap原理?
参考:https://www.cnblogs.com/yuanblog/p/4441017.html(推荐) https://blog.csdn.net/a745233700/article/deta ...
- HBase笔记:对HBase原理的简单理解
早些时候学习hadoop的技术,我一直对里面两项技术倍感困惑,一个是zookeeper,一个就是Hbase了.现在有机会专职做大数据相关的项目,终于看到了HBase实战的项目,也因此有机会搞懂Hbas ...
- 编译原理(简单自动词法分析器LEX)
编译原理(简单自动词法分析器LEX)源程序下载地址: http://files.cnblogs.com/files/hujunzheng/%E6%B1%87%E7%BC%96%E5%8E%9F%E7 ...
- Optaplanner规划引擎的工作原理及简单示例(2)
开篇 在前面一篇关于规划引擎Optapalnner的文章里(Optaplanner规划引擎的工作原理及简单示例(1)),老农介绍了应用Optaplanner过程中需要掌握的一些基本概念,这些概念有且于 ...
随机推荐
- 安装VUE教程
这段时间公司要准备开始用VUE,安装的过程中就遇到各种奇葩问题 1.Node.js安装 https://nodejs.org/en/download/ 安装好noedeJS然后继续安装下一步 3.执行 ...
- PythonDay16
第十六章模块 今日内容 自定义模块 time模块 datetime模块 rendom模块 自定义模块 # import 模块 例:import time# 导入的是time模块中所有的内容(变量,函数 ...
- sql server 平方根函数SQRT(x)
--SQRT(x)返回非负数x的二次方根 示例:select SQRT(9), SQRT(36); 结果:3 6
- NTFS,FAT32和exFAT文件系统的区别
NTFS,FAT32和exFAT文件系统的区别 本文所有资料来源于网络,仅做个人学习使用,如有侵权,请联系删除 1.什么是文件系统 文件系统是系统对文件的存放排列方式,不同格式的文件系统关系到数据是如 ...
- java压缩文件中文名乱码问题
import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; 改为 import org.apache.tools.zip. ...
- 【vsCode】识别.vue/一键生成.vue模板文件
1.安装插件Vetur 结果 ---> .vue代码识别彩标 2.配置.vue文件模板,以便快速一键生成格式化 2.1新建代码片段 File->Preferences->User S ...
- kickstart一键装机部署
1.第一步安装DHCP yum -y install dhcp 1.1配置修改文件 cat >> /etc/dhcp/dhcpd.conf <<END subnet 172.1 ...
- linux各路径(目录)的解释
目录 /bin 存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里. /etc 存放系统管理和配置文件 /home 存放所有用户文件的根目录,是用户主目录的基点, 比如用户use ...
- 四、Vue CLI-异步请求(axios)
一.模块的安装 npm install axios --save #--save可以不用写 如图: 二.配置main.js import axios from 'axios' Vue.prototyp ...
- 关于WPA/WPA2 4次握手
简单描述一下WPA/WPA2的4次握手中的一些关键词: WPA/WPA2使用4次握手的方式来产生所需要的密钥.四次握手通过一系列的交互,从PMK(Pairwise Master Key)生成PTK(P ...