手写一个简单的HashMap

HashMap

Hash:Hash散列将一个任意的长度通过某种(hash算法)算法转换成一个固定值。 移位
Map:地图x,y 存储

工作原理:通过hash算法,通过put和get存储和获取对象。

存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Factor则resize为原来的2倍)。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来。如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。

总结:通过hash出来的值,然后通过值定位到这个map,然后value存储到这个map中hashmap基本原理

手写源码

1.map接口

下面是我手写的hashmap

package map;
public interface Map<K,V> {
public V put(K k,V v);
public V get(K k);
public int size();
public interface Entry<K,V>{
	public  K setKey();
	public V getValue();
}
}

2.实现HashMap

package map;
public class HashMap<K,V> implements Map<K, V> {
private static int defaultLength=16;
private static double defaultLoader=0.75;
private Entry<K,V> [] table=null;
private int size=0;
public HashMap() {
	this(defaultLength,defaultLoader);
}
public HashMap(int length,double loader) {
	defaultLength=length;
	defaultLoader=loader;
	table=new Entry[defaultLength];
}
@Override
public V put(K k, V v) {
	size++;
	int index=hash(k); 
	Entry<K,V> entry=table[index];
	if(entry==null) {//判断是否已经创建
		table[index]=newEntry(k,v,null);
	}else {
		table[index]=newEntry(k,v,entry);
	}
	return table[index].getValue();
}
public Entry<K,V> newEntry(K k, V v, Entry<K,V> next) {
	return new Entry<K,V>(k,v,next);
}
public int hash(K k) {
	int m=defaultLength;
	int i=k.hashCode()%m; //得到哈希值取模
	return i>=0?1:-i;
}
@Override
public V get(K k) {
	int index=hash(k);
	if(table[index]==null) { //判断是否找到
		return null;
	}
	return find(k,table[index]);
	
}
public V find(K k, HashMap<K, V>.Entry<K, V> entry) {
	if(k==entry.getK()||k.equals((entry.getK()))){ //判断key值是否相等
		return entry.getV();
	}else {
		if(entry.next!=null) { //不相等从next里继续往下找
			return find(k,entry.next);
		}
	}
	return null;
}
@Override
public int size() {
	return 0;
}
class Entry<K,V> implements Map.Entry<K, V>{
	K k;
	V v;
	Entry<K,V> next;
	public Entry(K k,V v,Entry<K,V> next) {
		this.k=k;
		this.v=v;
		this.next=next;
	}
	public K getK() {
		return k;
	}
	public void setK(K k) {
		this.k = k;
	}
	public V getV() {
		return v;
	}
	public void setV(V v) {
		this.v = v;
	}
	public Entry<K, V> getNext() {
		return next;
	}
	public void setNext(Entry<K, V> next) {
		this.next = next;
	}
	@Override
	public K setKey() {
		return null;
	}
	@Override
	public V getValue() {
		return null;
	}
}
}

不足之处(伸缩性角度)

Key是否重复相关

1.伸缩性

2.时间复杂度:你的hash算法决定了你的效率

伸缩性角度:每当hashmap扩容的时候需要重新去addentry对象,需要Hash。然后放入我们新的entry table的数组里
如果你们的工作中你知道你们hashmap需要存多少值 几千或几万的时候最好先指定他们的扩容大小 防止在put的时候进行再次扩容很多次

全部评论

相关推荐

牛客245670684号:虚拟货币预测正确率百分之99,还要找工作干嘛,不早就财富自由了
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务