public interface DIYMap<K,V> {
public V put(K key, V value);
public V get(K key);
interface Entry<K,V> {
Entry<?,?> next = null;
public K getKey();
public V getValue();
}
}
package collection;
import java.util.ArrayList;
public class DIYHashMap<K,V> implements DIYMap<K,V>{
// 定义初始化默认数组长度
private int defaultLength = 16;
// 定义默认负载因子
private double defaultAddSizeFactor = 0.75;
// 使用数组位置的总数
private int useSize;
// 定义骨架Entry数组
private Entry<K,V> [] table;
// tableSize()函数为了保证数组长度是2的幂
// 为了hash散列的时候保持均匀分布,提高空间的利用效率
public int tableSizeFor(int n) {
int num = n-1;
num |= num>>>1;
num |= num>>>2;
num |= num>>>4;
num |= num>>>8;
num |= num >>>16;
return (num<0) ? 1:((num>=1<<30)?1<<30:num+1);
}
public DIYHashMap(int defaultLength, double defaultAddSizeFactor) {
if(defaultLength < 0) {
throw new IllegalAccessError("数组长度为负数");
}
if(defaultAddSizeFactor <= 0 || Double.isNaN(defaultAddSizeFactor)) {
throw new IllegalAccessError("扩容长度不能为非数字");
}
this.defaultLength = defaultLength;
this.defaultAddSizeFactor = defaultAddSizeFactor;
}
public DIYHashMap() {}
private class Entry<K,V> implements DIYMap.Entry<K,V> {
Entry<K,V> next = null;
K k;
V v;
public Entry(K k, V v, Entry<K,V> next) {
this.k = k;
this.v = v;
this.next = next;
}
@Override
public K getKey() {
return k;
}
public V getValue() {
return v;
}
}
/**
* 在put一个元素之前,先进行检查 查看当前已经使用的容量useSize是否超过了当前的负载因子,
* 或者是没有进行数组分配.如果是,进行扩容,将数组初始化,或者两倍扩展
*
*/
@Override
public V put(K key, V value) {
//查看useSize是否超过了当前的负载因子
if(table.length ==0 || useSize > defaultAddSizeFactor*defaultLength) {
up2Size();
}
//求出需要put的元素被放置的索引getIndex() hash散列算法
int index = getIndex(key,table.length);
Entry<K,V> entry = table[index];
// 构造一个新的Entry插入到Map中
Entry<K,V> newEntry = new Entry<K,V>(key,value, null);
// 索引为空 直接插入到数组中
if(entry == null) {
table[index] = newEntry;
useSize++;
//不为空 发生了hash冲突 需要将新值放在table[index].next位置
} else {
Entry<K,V> tmp;
while ((tmp = table[index]) != null) {
tmp = tmp.next;
}
tmp.next = newEntry;
}
return newEntry.getValue();
}
/**
* 在up2Size()中,重点在于数据如何rehash,这里采用ArrayList将旧的所有元素导出,
* 重新进行hash计算新的index进行导入到新的数组中
*/
public void up2Size() {
Entry<K,V> [] newTable = new Entry[defaultLength*2];
ArrayList<Entry<K,V>> entryList = new ArrayList<Entry<K,V>>();
for(int i=0;i<table.length;i++) {
if(table[i]==null) {
continue;
}
findEntryByNext(table[i],entryList);
}
if(entryList.size()>0) {
useSize = 0;
defaultLength = defaultLength*2;
table = newTable;
for(Entry<K,V> entry : entryList) {
if(entry.next != null) {
entry.next = null;
}
put(entry.getKey(), entry.getValue());
}
} else {
table = new Entry[defaultLength];
}
}
public void findEntryByNext(Entry<K,V> entry, ArrayList<Entry<K,V>> entryList) {
if(entry != null && entry.next != null) {
entryList.add(entry);
findEntryByNext(entry.next, entryList);
} else {
entryList.add(entry);
}
}
// 这边的重点在于hash算法,保证分布均匀
private int getIndex(K k, int length) {
int m = length -1;
int hashCode = k.hashCode();
hashCode = hashCode^((hashCode>>>7)^(hashCode>>>12));
hashCode = hashCode^((hashCode>>>7)^(hashCode>>>4));
int index = hashCode & m;
return index>=0 ? index:-index;
}
@Override
public V get(K key) {
return null;
}
}