目录
-----第一章
----------为什么要深入学习HashMap?
----------HashMap与HashTable的区别是什么?
----------自定义HashMap中的Entry<K,V>类
----------使用ArrayList集合实现简易版HashMap
----------使用LinkedList链表实现简易版HashMap
----------HashCode和equals的区别
----------如何解决HashCode碰撞问题
----------纯手写HashMap中的put方法
----------纯手写HashMap中的get方法
-----第二章
----------HashSet基本API使用介绍
----------HashSet底层原理分析
----------HashMap底层基本实现原理分析
----------HashMap构造函数实现原理分析
----------HashMap第一次数组扩容原理
----------HashMapPut方法源码分析
-----第三章
----------HashMapJDK1.7面试题总结
----------HashMapJDK1.7扩容死循环原理分析
----------HashMapJDK1.8什么要使用红黑树
----------数据结构中时间复杂度对比
----------二叉搜索树基本实现原理与思想
----------手写二叉搜索树添加功能
----------手写二叉搜索树查询功能
----------总结二叉搜索查询存在哪些问题
-----第四章
----------二叉搜索树存在那些问题
----------红黑树的数据结构基本介绍
----------红黑树基本的特征介绍
----------红黑树变换颜色的规则要求
----------红黑树左右旋转基本的规则
----------手写红黑树环境代码实现
----------手写红黑树实现二叉树
----------红黑树规则破坏如何实现修复
-----第五章
----------手写红黑树左旋转代码演示
----------红黑树基本变色旋转规则回顾
----------纯手写一步一步写左旋转
----------红黑树基本左旋变颜色01
----------红黑树基本左旋变颜色02
----------红黑树基本左旋变颜色03
----------红黑树基本左旋变颜色04
----------红黑树查询左大值与最小值
-----第六章
----------HashMap8基本实现原理分析
----------HashMap8优化了7那些bug
----------HashMap8的Put方法实现原理01
----------HashMap8的Put方法实现原理02
----------HashMap8的Put方法扩容实现
----------HashMap8的Put方法源码分析总结
使用LinkedList链表实现HashMap
第一步:在HashMap中创建一个AaaryList集合来存放Entry<K,V>对象
private LinkedList<Entry>[] list= new LinkedList[100];
第二步:使用简易的Hash算法,来提高查询效率
private int hash(K key) {
int hashCode = key.hashCode();
int hash = hashCode % list.length;
return hash;
}
第三步:重写put方法
public V put(K key, V value) {
// 1.计算到hash值
int hash = hash(key);
// 2.取出该位置的链表
LinkedList<Entry> linkedList = list[hash];
// 3.使用Key,Value创建Entry对象
Entry entry = new Entry(key, value);
//4.如果链表为null时
if (linkedList == null) {
// 5.创建链表
linkedList = new LinkedList();
// 6.把Entry对象添加到linkedList链表中
linkedList.add(entry);
// 7.数组指定位置存放链表
list[hash] = linkedList;
return value;
}
// 4.如果链表存在,遍历链表,判断Key是否存在
for (Entry e : linkedList) {
// 5.存在相同Key,覆盖旧值
if (e.getKey().equals(key)) {
e.setValue(value);
return value;
}
}
// 6.hashCode相同但是Key不同
linkedList.add(entry);
list[hash] = linkedList;
return value;
}
第四步:重写get方法
public V get(K key) {
// 1.计算Hash值
int hash = hash(key);
// 2.获得指定下标的链表
LinkedList<Entry> linkedList = list[hash];
// 3.判断链表是否为null
if (linkedList != null) {
// 4. 遍历链表
for (Entry e: linkedList) {
// 5.取出Key相同的value值
if (e.getKey().equals(key)) {
return (V) e.getValue();
}
}
}
return null;
}
这时HashMap如下
public class MyHashMap<K, V> implements MyMap<K, V> {
private LinkedList<Entry>[] list= new LinkedList[100];
private int hash(K key) {
int hashCode = key.hashCode();
int hash = hashCode % list.length;
return hash;
}
public V put(K key, V value) {
// 1.计算到hash值
int hash = hash(key);
// 2.取出该位置的链表
LinkedList<Entry> linkedList = list[hash];
// 3.使用Key,Value创建Entry对象
Entry entry = new Entry(key, value);
//4.如果链表为null时
if (linkedList == null) {
// 5.创建链表
linkedList = new LinkedList();
// 6.把Entry对象添加到linkedList链表中
linkedList.add(entry);
// 7.数组指定位置存放链表
list[hash] = linkedList;
return value;
}
// 4.如果链表存在,遍历链表,判断Key是否存在
for (Entry e : linkedList) {
// 5.存在相同Key,覆盖旧值
if (e.getKey().equals(key)) {
e.setValue(value);
return value;
}
}
// 6.hashCode相同但是Key不同
linkedList.add(entry);
list[hash] = linkedList;
return value;
}
public V get(K key) {
// 1.计算Hash值
int hash = hash(key);
// 2.获得指定下标的链表
LinkedList<Entry> linkedList = list[hash];
// 3.判断链表是否为null
if (linkedList != null) {
// 4. 遍历链表
for (Entry e: linkedList) {
// 5.取出Key相同的value值
if (e.getKey().equals(key)) {
return (V) e.getValue();
}
}
}
return null;
}
static class Entry<K, V> implements MyMap.Entry<K, V> {
private K k;
private V v;
public Entry(K k, V v) {
this.k = k;
this.v = v;
}
public K getKey() {
return this.k;
}
public V getValue() {
return this.v;
}
}
}
这样用LinkedList链表就实现了一个简单的HashMap了,这样有什么缺点吗?
数组容量是固定的,当通过Hash方法计算出来的值相同的越来越多的时候,链表的长度就会越来越长,这时候get方法的时间复杂度就是O(n)了
这时候我们就应该去考虑扩容的问题了,什么时候该扩容?扩容多大?这个问题在JDK1.7的HashMap中有了解决方案