忙里偷闲,写了个 自己的HashMap,没有使用红黑树,仅是数组+单向链表的方式;
唯一的收货,大概就是理解了,为何阿里代码开发规范中,要求指定初始化的容量:因为每一次的resize都相当于,都是一个O(N)的操作;
/**
* 基于数组+链表实现的hashMap
*
* @param <K>
* @param <V>
*/
public class MyHashMap<K, V> {
static class Entry<K, V> {
K k;
V v;
Entry next;
int hash;
Entry(K k, V v, Entry next, int hash) {
this.k = k;
this.v = v;
this.next = next;
this.hash = hash;
}
}
Entry[] table;
int size;
int capacity;
static int default_capacity = 16;
float threshold;
static float default_threshold = 0.75f;
public MyHashMap(int capacity, float threshold) {
this.capacity = size < 2 << 4 ? default_capacity : capacity;
this.threshold = threshold < 0 || Float.isNaN(threshold) ? default_threshold : threshold;
table = new Entry[this.capacity];
}
public MyHashMap(int capacity) {
this(capacity, default_threshold);
}
public MyHashMap() {
this(default_capacity, default_threshold);
}
public V put(K k, V v) throws Exception {
size++;
resize(size);
int index = hash(k);
Entry<K, V> indexEntry = table[index];
if (indexEntry == null) {
indexEntry = new Entry<>(k, v, null, k == null ? 0 : k.hashCode());
table[index] = indexEntry;
return indexEntry.v;
}
while (indexEntry != null && indexEntry.next != null) {
if (indexEntry.k.equals(k)) {
V oldV = indexEntry.v;
indexEntry.v = v;
size--;
return oldV;
} else {
indexEntry = indexEntry.next;
}
}
if ((indexEntry.k == null && null == k) || (indexEntry.k != null && indexEntry.k.equals(k))) {
V oldV = indexEntry.v;
indexEntry.v = v;
size--;
return oldV;
} else {
indexEntry.next = new Entry(k, v, null, k.hashCode());
}
return v;
}
public V get(K k) throws Exception {
int index = hash(k);
Entry<K, V> indexEntry = table[index];
while (indexEntry != null) {
if ((indexEntry.k == null && null == k) || (indexEntry.k != null && indexEntry.k.equals(k))) {
return indexEntry.v;
} else {
indexEntry = indexEntry.next;
}
}
return null;
}
int hash(K k) {
if (k == null) {
return 0;
}
int index = k.hashCode() % capacity;
return index;
}
void resize(int size) {
if (size >= capacity * threshold) {
capacity = capacity << 1;
Entry[] oldTable = table;
Entry[] newTable = new Entry[capacity];
transfer(newTable);
table = newTable;
}
}
/**
* 这就是构造器中指定capacity的原因,因为每一次扩容都是 O(N)
*
* @param newTable
*/
void transfer(Entry[] newTable) {
for (Entry<K, V> e : table) {
while (null != e) {
Entry next = e.next;
int index = hash(e.k);
Entry<K, V> entry = newTable[index];
e.next = entry;
newTable[index] = e;
e = next;
}
}
}
public static void main(String[] args) throws Exception {
MyHashMap<String, String> myHashMap = new MyHashMap<>();
myHashMap.put(null, "null");
System.out.println(myHashMap.get(null));
myHashMap.put("1", "1");
myHashMap.put("2", "2");
myHashMap.put("3", "3");
myHashMap.put("4", "4");
myHashMap.put("5", "5");
myHashMap.put("6", "6");
myHashMap.put("7", "7");
myHashMap.put("8", "8");
myHashMap.put("9", "9");
myHashMap.put("10", "10");
myHashMap.put("11", "11");
myHashMap.put("12", "12");
myHashMap.put("13", "13");
myHashMap.put("14", "14");
myHashMap.put("15", "15");
myHashMap.put("16", "16");
myHashMap.put("17", "17");
myHashMap.put("18", "18");
myHashMap.put("19", "19");
myHashMap.put("20", "20");
System.out.println(myHashMap.get("1"));
System.out.println(myHashMap.get("2"));
System.out.println(myHashMap.get("3"));
System.out.println(myHashMap.get("4"));
System.out.println(myHashMap.get("5"));
System.out.println(myHashMap.get("6"));
System.out.println(myHashMap.get("7"));
System.out.println(myHashMap.get("8"));
System.out.println(myHashMap.get("9"));
System.out.println(myHashMap.get("10"));
System.out.println(myHashMap.get("11"));
System.out.println(myHashMap.get("12"));
System.out.println(myHashMap.get("13"));
System.out.println(myHashMap.get("14"));
System.out.println(myHashMap.get("15"));
System.out.println(myHashMap.get("16"));
System.out.println(myHashMap.get("17"));
System.out.println(myHashMap.get("18"));
System.out.println(myHashMap.get("19"));
System.out.println(myHashMap.get("20"));
System.out.println(myHashMap.size);
}
}