看这篇文章前,不妨看我的上一篇文章:每日一省之————利用数组和链表实现一个简单的HashMap。这样一来,相信大家对Java中的HashMap会有一个更全面的认识。好了,废话不多说了,直接上代码吧:
import java.util.LinkedList;
import java.util.Queue;
public class LinearProbingHashMap<K, V> {
public static final int INITIAL_CAPACITY = 4;
private int N;
private int M;
private K[] keys;
private V[] values;
public LinearProbingHashMap(int arrayLength) {
this.M = arrayLength;
keys = (K[]) new Object[M];
values = (V[]) new Object[M];
}
public LinearProbingHashMap() {
this(INITIAL_CAPACITY);
}
public int size() {
return N;
}
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(K key) {
if (key == null)
throw new NullPointerException("参数不能为null");
return get(key) != null;
}
private int hash(K key) {
return (key.hashCode() & 0x7fffffff) % M;
}
/*
* 不扩容会导致无限循环,why?大家自己思考哦
*/
private void resize(int arrayLength) {
LinearProbingHashMap<K, V> temp = new LinearProbingHashMap<K, V>(arrayLength);
for (int i = 0; i < M; i++) {
if (keys[i] != null) {
temp.put(keys[i], values[i]);
}
}
keys = temp.keys;
values = temp.values;
M = temp.M;
}
// hash()对应的索引位置被占用,则放置到相邻的下一个位置,如果下一个位置也被占用,则
// 放置到下下一个相邻位置
public void put(K key, V value) {
if (key == null)
throw new NullPointerException("key不能为null");
if (value == null) {
remove(key);
return;
}
if (N >= M / 2)
resize(2 * M);
int i;
for (i = hash(key); keys[i] != null; i = (i + 1) % M) {
if (keys[i].equals(key)) {
values[i] = value;
return;
}
}
keys[i] = key;
values[i] = value;
N++;
}
public V get(K key) {
if (key == null)
throw new NullPointerException("参数不能为null");
for (int i = hash(key); keys[i] != null; i = (i + 1) % M)
if (keys[i].equals(key))
return values[i];
return null;
}
public void remove(K key) {
if (key == null)
throw new NullPointerException("key不能为null");
if (!contains(key))
return;
int i = hash(key);
while (!key.equals(keys[i])) {
i = (i + 1) % M;
}
keys[i] = null;
values[i] = null;
// 重新散列位于同一个段里的所有键,否则,删除一个键之后,则与被删除的键有相同散列值的键即使存在于散列表中,但查找却有可能查找不到。
// why? 大家可以参见存放键的方式,也即put方法
i = (i + 1) % M;
while (keys[i] != null) {
K keyNeedToRehash = keys[i];
V valueNeedToRehash = values[i];
keys[i] = null;
values[i] = null;
N--;
put(keyNeedToRehash, valueNeedToRehash);
i = (i + 1) % M;
}
N--;
if (N > 0 && N <= M / 8)
resize(M / 2);
assert isValid();
}
// 用于判断我们实现的散列表到底有没有与实现逻辑相互冲突
private boolean isValid() {
if (M < 2 * N) {
System.err.println("散列表没有按照预期进行扩容");
return false;
}
for (int i = 0; i < M; i++) {
if (keys[i] == null)
continue;
else if (get(keys[i]) != values[i]) {
System.err.println("存在数据不一致问题!");
return false;
}
}
return true;
}
public Iterable<K> keys() {
Queue<K> queue = new LinkedList<K>();
for (int i = 0; i < M; i++)
if (keys[i] != null)
queue.offer(keys[i]);
return queue;
}
/**
* 测试方法
*
* @param args
*/
public static void main(String... args) {
LinearProbingHashMap<String, Integer> map = new LinearProbingHashMap<String, Integer>();
map.put("lhever", 100);
map.put("david", 100);
map.put("kate", 100);
System.out.println("this size is :" + map.size());
map.remove("lhever");
System.out.println("this size is :" + map.size());
map.remove("david");
map.remove("chris");
System.out.println("this size is :" + map.size());
map.put("kaven", 100);
map.put("downald", 100);
map.put("garry", 100);
map.put("json", 100);
for (String key : (Iterable<String>) map.keys()) {
System.out.println(key + " : " + map.get(key));
}
}
}