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过程中需要掌握的一些基本概念,这些概念有且于 ...
随机推荐
- Nginx与PHP如何协同工作
要说Nginx与PHP如何协同工作,首先得说CGI和FastCGI两个协议. CGI是Web Server与后台语言交互的协议,有了这个协议,开发者可以使用任何语言处理Web Server发来的请求, ...
- 作业调度框架Quartz.NET-现学现用-01-快速入门 - 简书
原文:作业调度框架Quartz.NET-现学现用-01-快速入门 - 简书 前言 你需要应用执行一个任务吗?这个任务每天或每周星期二晚上11:30,或许仅仅每个月的最后一天执行.一个自动执行而无须干预 ...
- openlayers之地图测距侧面
项目背景vue-cli3.0 public下html需要引入文件 <link rel="stylesheet" href="<%= BASE_URL %> ...
- linux系统批量修改root密码
#!/bin/bash ip_list=(192.168.36.12 192.168.36.13) remote_cmd="echo new-passwd | passwd --stdin ...
- 021-Zabbix4.2对IIS监控摸索记录
Zabbix是很强大,但是相关的细节技术文档貌似很少,摸索之路就显得异常难. 度娘搜了下,关于Zabbix对IIS的监控资料确实有,确实也讲如何操作了,但是细细按照对方的要求操作下,总是缺数据,no ...
- linux编译安装mysql5.7
一.下载源码包 -src cd /usr/local/src/mysql--src wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5 ...
- 百度贴吧自动回帖的两种方式,使用requests(urllib2)和selenium两种方式回帖
本文介绍,回复贴吧指定某楼层主的帖子的方法.在这里不介绍无限发主贴和无限回复主贴的方法,无限发主题帖会爆吧,引起别人的反感,并且很容易遭到吧主的封杀:无限回主题帖,会让整个帖子的每楼的回复充满了自己的 ...
- error: ‘ostream_iterator’ was not declared in this scope
在代码中添加 #include <iterator>
- linux shell鼠标键盘快捷键
- mysqldump导出时 --set-gtid-purged=OFF
mysqldump导出表 [root@bj db10044]# rpm -qf `which mysqldump`Percona-Server-client-56-5.6.22-rel71.0.el6 ...