手写迷你hashMap
作者:互联网
public interface MyMap<K,V> {
V put(K k,V v);
V get(K k);
interface Entry<K,V>{
K getKey();
V getValue();
}
}
public class MyHashMap<K,V> implements MyMap<K,V> {
//默认容量
private static int defaultLength = 16;
//加载因子
private static float defaultLoad = 0.75f;
//Map使用数组长度
private int size = 0;
//声明数组
private Entry<K,V>[] map = null;
public MyHashMap(){
map = new Entry[defaultLength];
}
/**
* 储存结构
* @param <K>
* @param <V>
*/
@Setter
@Getter
class Entry<K,V> implements MyMap.Entry<K,V>{
private K key;
private V value;
//下标
int index;
//链表指向下一个
private Entry<K,V> next;
public Entry(K k,V v,Entry<K,V> entry,int inx){
this.key = k;
this.value = v;
this.index = inx;
this.next = entry;
}
}
-
put方法被调用时,HashMap会根据key计算出对应的hashcode,然后根据hashcode确定该Entity应该存放在数组的哪个位置
-
HashMap发生hash碰撞如果发现hashcode已经存在,则会对key进行euqals对比
-
equals结果是true,则认为确实是同一个key,然后将新的value覆盖旧的value(此时put方法将会返回旧value值)。
-
equals结果是false,则认为是hash碰撞,此时会将之前的Entity作为新Entity的next,此时形成一个链表,新Entity则处在链表的首位。
public V put(K k, V v) { int index = getIndex(k,map.length); Entry<K,V> entry = map[index]; if(entry == null){ map[index] = new Entry(k,v,null,index); } else { while (entry.next != null) { if (k.equals(entry.getKey())) { entry.value = v; } } map[index] = new Entry(k, v, entry, index); } size++; if(size > defaultLength*defaultLoad){ resize(); } System.out.println("添加 key:"+k+"成功下标"+index); return v;
}
/**
- 获取下标
- @param k 键值
- @return length 下标
*/
private int getIndex(K k,int length){
int m = length -1 ;
return k.hashCode() & m;
}
根据key计算hashcode,然后得出其数组下标,去对应位置获取链表。
从头到尾遍历链表的每一个Entity,通过equals方法找到对应的Entity。
public V get(K k) {
int index = getIndex(k,map.length);
Entry<K, V> entry = map[index];
while (entry != null && entry.next != null) {
if (entry.getKey() == k || (entry.getKey() != null && entry.getKey().equals(k))) {
return entry.getValue();
} else {
entry = entry.next;
}
}
if (entry.next == null) {
if (entry.getKey() == k || (entry.getKey() != null && entry.getKey().equals(k))) {
return entry.getValue();
}
}
return null;
}
阈值=容量*加载因子。默认12。当元素数量超过阈值时便会触发扩容,每次增长都是2倍
private void resize() {
Entry<K,V>[] newMap = new Entry[2*defaultLength];
System.out.println("开始进行扩容,扩容前大小:"+ map.length);
Entry[] oldMap = map;
for (int j = 0; j < oldMap.length; j++) {
Entry<K,V> e = oldMap[j];
if (e != null) {
oldMap[j] = null;
do {
Entry<K,V> next = e.next;
//当数组扩容后需要数组数量按新map重新计算每个元素的下标,否则读取时计算下表出错
int i = getIndex(e.key,newMap.length);
e.next = newMap[i];
newMap[i] = e;
e = next;
} while (e != null);
}
}
map = newMap;
//扩容成功 更新数组长度
defaultLength = 2*defaultLength;
System.out.println("开始进行扩容,扩容后大小:"+ map.length);
}
下篇文章更新链表转换红黑树
标签:map,hashMap,迷你,index,next,Entry,entry,手写,null 来源: https://blog.csdn.net/weixin_43861113/article/details/118366795