相关概念:
什么叫hash:就是把一个不固定的长度的二进制值映射成固定长度的二进制值
12%10 = 2 也等于2
代码部分:
package com.yz.hashmap; import java.util.ArrayList; import java.util.List; /** * 自定义HashMap * Created by yz on 2018/2/24. */ public class YZHashMap<K,V> implements YZMap<K,V>{ /** * hash表的默认长度 */ private static int defaultLength = 16; /** * 负载因子 就是一个阈值 扩容 如果表的长度超过了0.75,既16*0.75=12 就要扩容了 */ private static double defalutLoader = 0.75; //存储数据的地方 private Entry<K,V>[] table = null; //表里面元素个数 表存储几个元素了 private int size = 0; /** * 有参构造方法 初始化hash表的默认长度 ,负载因子,table长度 * @param length * @param loader */ YZHashMap(int length ,double loader){ this.defaultLength = length; this.defalutLoader =loader; table = new Entry[defaultLength]; } /** * 无参构造函数 调用有参构造 */ YZHashMap(){ this(defaultLength,defalutLoader); } /** * 需要把k v 数据存储到hash表里面 * @param k * @param v * @return */ public V put(K k, V v) { //判断表的长度是否需要扩容 if(size >= defaultLength * defalutLoader){ up2size(); } int index = getIndex(k); //根据表中位置取对象 Entry<K, V> entry = table[index]; if(entry == null){ //第一次存储 table[index] = newEntry(k,v,null); size++; }else{ //如果该位置已经存在数据了,占用原数据的位置,并将指针指向原数据(entry) 这个两个entry的index的位置一样,但是指针不一样了 table[index] = newEntry(k,v,entry); } return table[index].getValue(); } /** * 扩容,标准扩一倍 长度16扩32 */ private void up2size(){ //扩容以后,老表原来的数据的位置要重新计算,因为index是根据key的hashCode % 表(不管是新表还是老表)的长度获取的值 int index = k.hashCode() % m; 再散列,从新分配index位置 Entry<K,V>[] newTable = new Entry[2 * defaultLength]; againHash(newTable); } /** * 扩容后再散列,从新分配老表位置 * @param newTable */ private void againHash(Entry<K,V>[] newTable){ //1.拿到前面老表的数据 ListK,V>> list = new ArrayList K, V>>(); for(int i=0;i<table.length;i++){ if(table[i] == null){ continue; } findEntryByNext(table[i],list); } //获取到数据 if(list.size() > 0){ //初始化 size = 0 ; defaultLength = defaultLength * 2; table = newTable; for(Entry<K,V> entry : list){ if(entry.next != null){ entry.next = null; } //将原数据全部存储到扩容的数组中 put(entry.getKey(),entry.getValue()); } } } /** * 获取老表的全部元素,含链表元素,因为老表可能存在链表结构,递归免不了的 * next指向的就是entry对象 * @param entry * @param list */ private void findEntryByNext(Entry<K,V> entry,List K,V>> list){ if(entry != null && entry.next != null){ list.add(entry); //如果链表下面还有元素,使用递归 findEntryByNext(entry.next,list); }else{ list.add(entry); } } /** * 实例化Entry对象 * @param k * @param v * @param next * @return */ private Entry<K,V> newEntry(K k,V v,Entry<K,V> next){ return new Entry(k,v,next); } /** * hash算法 获取key对应的索引,根据key的hash值对表的长度取模,得到的index就是在表中的存储位置 * @param k * @return */ private int getIndex(K k){ int m = defaultLength; int index = k.hashCode() % m; return index >=0 ? index : -index; } /** * 根据key递归去找对应的value值 * @param k * @return */ public V get(K k) { int index = getIndex(k); if(table[index] == null){ return null; } return findValueByEqualKey(k,table[index]); } /** * 链表中index一样情况下,entry的key不一样 * 根据key拿到对应的数据 * @param k * @param entry * @return */ private V findValueByEqualKey(K k , Entry<K,V> entry){ if(k == entry.getKey() || k.equals(entry.getKey())){ return entry.getValue(); }else{ //如果不相等,继续找,使用递归 if(entry.next != null){ return findValueByEqualKey(k,entry.next); } } return null; } public int size() { return 0; } /** * 实现YZMap接口内部类 */ class Entry<K,V> implements YZMap.Entry<K,V>{ K k; V v; //next 指针指向另一个对象 Entry<K,V> next; //构造方法,初始化三个值 Entry(K k,V v,Entry<K,V> next){ this.k = k; this.v = v; this.next = next; } public K getKey() { return k; } public V getValue() { return v; } } }
package com.yz.hashmap; /** * 自定义map接口 * Created by yz on 2018/2/24. */ public interface YZMap<K,V> { //把key value属性包装成对象存储到hash表中 V put(K k,V v); //根据key获取value V get(K k); //获取表的长度 int size(); /** * 内部接口,entry对象实际上就是存储到hash表里面的数据对象 * key vlaue next * @param* @param */ interface Entry<K,V>{ //获取key K getKey(); //获取value V getValue(); } }
package com.yz.hashmap; import java.util.HashMap; import java.util.Map; /** * Created by yz on 2018/2/24. */ public class MyTest { public static void main(String[] args) { Mapjdkmap = new HashMap (); Long t1 = System.currentTimeMillis(); for(int i=0;i<1000;i++){ jdkmap.put("yz"+i,"test"+i); } for(int i=0;i<1000;i++){ System.out.println(jdkmap.get("yz"+i)); } Long t2 = System.currentTimeMillis(); System.out.println("jdk time: "+(t2-t1)); System.out.println("------------------------"); YZMap yzmap = new YZHashMap (); Long t3 = System.currentTimeMillis(); for(int i=0;i<1000;i++){ yzmap.put("yz"+i,"test"+i); } for(int i=0;i<1000;i++){ System.out.println(yzmap.get("yz"+i)); } Long t4 = System.currentTimeMillis(); System.out.println("yz time: "+(t4-t3)); } }