您的位置:首页 > 其它

实现自己的HashMap

2015-05-04 20:18 176 查看


看了HashMap源码,HashMap的结构采用的是数组+链表--Hash表,结合了数组寻找、存取和链表的易插入删除等优点。


HashMap的存取实现

     既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现:

//存储时:
int hash = key.hashCode();// 这个hashCode方法这里不详述,只要理解每个key的hash是一个固定的int值
int index = hash % Entry[].length;
Entry[index] = value;

//取值时:
int hash = key.hashCode();
int index = hash % Entry[].length;
return Entry[index];


到这里我们轻松的理解了HashMap通过键值对实现存取的基本原理


3.解决hash冲突的办法

开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列)
再哈希法
链地址法
建立一个公共溢出区

Java中hashmap的解决办法就是采用的链地址法。


4.实现自己的HashMap

 


Entry.java



package edu.sjtu.erplab.hash;

public class Entry<K,V>{
final K key;
V value;
Entry<K,V> next;//下一个结点

//构造函数
public Entry(K k, V v, Entry<K,V> n) {
key = k;
value = v;
next = n;
}

public final K getKey() {
return key;
}

public final V getValue() {
return value;
}

public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}

public final boolean equals(Object o) {
if (!(o instanceof Entry))
return false;
Entry e = (Entry)o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2)))
return true;
}
return false;
}

public final int hashCode() {
return (key==null   ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode());
}

public final String toString() {
return getKey() + "=" + getValue();
}

}



MyHashMap.java



package edu.sjtu.erplab.hash;

//保证key与value不为空
public class MyHashMap<K, V> {
private Entry[] table;//Entry数组表
static final int DEFAULT_INITIAL_CAPACITY = 16;//默认数组长度
private int size;

// 构造函数
public MyHashMap() {
table = new Entry[DEFAULT_INITIAL_CAPACITY];
size = DEFAULT_INITIAL_CAPACITY;
}

//获取数组长度
public int getSize() {
return size;
}

// 求index,采用异或运算,使hash表分布更加均匀
static int indexFor(int h, int length) {
return h & (length - 1);
}

//获取元素
public V get(Object key) {
if (key == null)
return null;
int hash = key.hashCode();// key的哈希值
int index = indexFor(hash, table.length);// 求key在数组中的下标
for (Entry<K, V> e = table[index]; e != null; e = e.next) {
Object k = e.key;
if (e.key.hashCode() == hash && (k == key || key.equals(k)))
return e.value;
}
return null;
}

// 添加元素
public V put(K key, V value) {
if (key == null)
return null;
int hash = key.hashCode();
int index = indexFor(hash, table.length);

// 如果添加的key已经存在,那么只需要修改value值即可
for (Entry<K, V> e = table[index]; e != null; e = e.next) {
Object k = e.key;
if (e.key.hashCode() == hash && (k == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
return oldValue;// 原来的value值
}
}
// 如果key值不存在,那么需要添加
Entry<K, V> e = table[index];// 获取当前数组中的e
table[index] = new Entry<K, V>(key, value, e);// 新建一个Entry,并将其指向原先的e
return null;
}

}



MyHashMapTest.java



package edu.sjtu.erplab.hash;

public class MyHashMapTest {

public static void main(String[] args) {

MyHashMap<Integer, Integer> map = new MyHashMap<Integer, Integer>();
map.put(2, 40);
map.put(2, 40);
map.put(17, 85);

System.out.println(map.get(2));
System.out.println(map.get(2));
System.out.println(map.get(17));
System.out.println(map.get(null));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息