手写实现HashMap1.7版本

Map接口

public interface MyMap<K,V> {
public V put(K k,V v);
public V get(K k);

/**
* 内部类
* @author mama
*
* @param <K>
* @param <V>
*/
public interface Entry<K,V>{
public K getKey();
public V getValue();
}
}


HashMap的结构

 

定义的成员变量:

1、定义默认数组的大小  1<<4

private static int defaultLenth=1<<4;

2、定义有限的数组长度空间位置内会形成链表 0.75

private static double defaultAddSizeFactor=0.75;

3、定义数组的位置

private int useSize;

4、定义一个Entry<K,V> table;

private Entry<K,V>[]table=null;

 

有一个内部类,定义了Entry

class Entry<K,V>implements MyMap.Entry<K, V>{

   

K k;

V v;

//指向被this挤压下去的Entry对象

Entry<K,V> next;

public Entry(Kk,V v,Entry<K,V> next) {

this.k=k;

this.v=v;

this.next=next;

}

@Override

public K getKey() {

// TODO Auto-generated method stub

return k;

}

 

@Override

public V getValue() {

// TODO Auto-generated method stub

return v;

}

}

 

定义构造类

1、无参的构造

public MyHashMap() {

this(defaultLenth,defaultAddSizeFactor);

}

2、有参的构造,传入数组的大小和元素占数组总容量形成链表的阈值0.75

public MyHashMap(int length,double defaultAddSizeFactor) {

if(length<0) {

throw new IllegalArgumentException("参数不能为负数"+length);

}

if(defaultAddSizeFactor<=0 || Double.isNaN(defaultAddSizeFactor)) {

throw new IllegalArgumentException("扩容标准必须是大于0的数字"+defaultAddSizeFactor);

}

this.defaultLenth=length;

this.defaultAddSizeFactor=defaultAddSizeFactor;

table=new Entry[defaultLenth];

}

 

 

定义put方法

//1、判断是否需要扩容

if(useSize>defaultLenth*defaultAddSizeFactor) {

//进行两倍的扩容

up2Size();

}

//如果这时扩容了,新数组扩容为2倍,老数组的数据被重新散列到新数组中

int index=getIndex(k,table.length);//得到了下标

Entry<K,V> entry=table[index];

//table[index]的entry为空,说明没有相同的元素,也就形成不了链表

if(entry==null) {

table[index] =new Entry(k,v,null);

useSize++;//使用位置被占用+1

}else if(entry!=null) {//说明说相同的值,挤压下去,形成链表

table[index] =new Entry(k,v,entry);

}

return table[index].getValue();

}

 

1、判断是否需要扩容

if(useSize>defaultLenth*defaultAddSizeFactor) {

//进行两倍的扩容

up2Size();

}

1.1、扩容的方法

private void up2Size() {

Entry<K,V>[] newTable=new Entry[2*defaultLenth];

//将老数组存的内容放到新数组,拿之前散列算法

//3.

againHash(newTable);

}

1.2、把老数组存到新数组的key值进行散列算法,在这之前把value存到list

private void againHash(MyHashMap<K, V>.Entry<K, V>[]newTable) {

List<Entry<K,V>> entryList=new ArrayList<MyHashMap<K,V>.Entry<K, V>>();

//找老数组中的对象

for (int i = 0;i < table.length;i++) {

//老数组没有数据

if(table[i]==null) {

continue;

}

//这个方法存找到不为空的对象存入entryList

foundEntryByNext(table[i],entryList);

}

//进行散列

if(entryList.size()>0) {

useSize=0;

defaultLenth=2*defaultLenth;

table=newTable;

for (Entry<K, V>entry : entryList) {

//说明遍历的EntryList是链表,取消链表结构,把指定的下一个entry。next为null

if(entry.next!=null) {

entry.next=null;//为什么要致为null,因为foundEntryByNext()递归,把数据存到了list中变成了链表,next就不用再指向下一个值了

}

//没有形成链表,调用put

put(entry.getKey(),entry.getValue());

}

}

}

 

1.3、把不为空的对象存到list---使用递归

private void foundEntryByNext(MyHashMap<K, V>.Entry<K, V>entry, List<MyHashMap<K, V>.Entry<K, V>>entryList) {

 if(entry!=null&&entry.next!=null) {

 entryList.add(entry);

 //递归

 foundEntryByNext(entry.next,entryList);

 }else {

 entryList.add(entry);//链表中只有一个

}

}

 

2、通过k和数组的长度范围,获取元素在数组中的位置的方法

private int getIndex(Kk, int length) {

//length 2^n 0000 1111

int m=length-1;

//保证index=【0,length)之间

int index=hash(k.hashCode()&m);//得到数组的位置(进行位运算)

return index;

}

 

2.1、按jdk1.7源码写的hash算法

private int hash(int hashCode) {

hashCode=hashCode^((hashCode>>>20)^(hashCode>>>12));

return hashCode^((hashCode>>>7)^(hashCode>>>4));

}

 

3、得到元素的对象,并且判断为空和不为空

if(entry==null) {

table[index] =new Entry(k,v,null);

useSize++;//使用位置被占用+1

}else if(entry!=null) {//说明说相同的值,挤压下去,形成链表

table[index] =new Entry(k,v,entry);

}

3.1、为空的话,说明没有相同的元素,也就形成不了链表,存入看,k,v和指向链表下一个的值为null,当前位置useSize得自增加一。

3.2、不为空,说明有相同的值,把老值挤压下去,形成链表,存入看,k,v和指向链表下一个

值不为空。

 

 

定义get方法

public V get(Kk) {

int index =getIndex(k,table.length);

if(table[index]==null) {

throw new NullPointerException();//报个空指针异常

}

//处理k存在的情况

return findValueByEqualKey(k,table[index]);

}

 

 

private V findValueByEqualKey(Kk, MyHashMap<K, V>.Entry<K, V> entry) {

if(k==entry.getKey() ||k.equals(entry.getKey())) {

return entry.getValue();

}else if (entry.next!=null) {//key不相等,hash相等

return findValueByEqualKey(k,entry.next);//调用递归找链表的下一个值

}

return null;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值