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过程中需要掌握的一些基本概念,这些概念有且于 ...
随机推荐
- 抖音很火的存钱计划,让python告诉你总共可以存到多少钱!
抖音上有个很火的存钱计划,说是第一天存1块钱,第二天存2块钱,第三天存3块钱.....依此类推存365天,总共可以存到多少钱,我们现在用python告诉你怎么做: #定个初始存入金额 money = ...
- 开发跨平台应用解决方案-uniapp 真心不错,支持一波
uni-app 是一个使用 Vue.js 开发跨平台应用的前端框架,开发者编写一套代码,可编译到iOS.Android.微信小程序等多个平台. 用了mui,H5+一年多了,感觉dcloud 最近推出的 ...
- Windows XP硬盘安装Ubuntu 16.04双系统图文详解
需要下载的东西有两个,一个是grub4dos,另一个是Ubuntu 16.04 LTS的镜像文件,具体下载地址如下: 1 2 3 1.grub4dos 点击下载 grub4dos 2 ...
- PyCharm专业版下载安装
目录 1. 推荐阅读 2. PyCharm专业版 (目录) 1. 推荐阅读 Python基础入门一文通 | Python2 与Python3及VSCode下载和安装.PyCharm安装.Python在 ...
- Ubuntu18.04 安装redis
Redis是常用基于内存的Key-Value数据库,比Memcache更先进,支持多种数据结构,高效,快速.用Redis可以很轻松解决高并发的数据访问问题:作为实时监控信号处理也非常不错. 安装red ...
- [DllImport("kernel32.dll")]使用
C#中读取ini配置文件 [DllImport("kernel32.dll")] using System;using System.Collections.Generic;usi ...
- TCP那些事儿
TCP 的那些事儿(上) TCP 的那些事儿(下)
- Spring MVC文件上传下载(转载)
原文地址: http://www.cnblogs.com/WJ-163/p/6269409.html 上传参考 http://www.cnblogs.com/lonecloud/p/5990060.h ...
- ajax 请求成功,但是后台feigin请求超时解决方案
========后台请求数据时间较长,报feigin超时错误====== fegin报错如下: feign.RetryableException: Read timed out executing P ...
- Excel去重操作
工作中经常遇到要对 Excel 中的某一列进行去重操作,得到不重复的结果,总结如下: 选中要操作的列(鼠标点击指定列的字母,如T列) 点击"数据"中"排序和筛选" ...