链地址法实现HashMap
Posted kuillldan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链地址法实现HashMap相关的知识,希望对你有一定的参考价值。
前注:本文介绍的HashMap并非Java类库的实现。而是根据哈希表知识的一个实现。
上文介绍了开放地址法实现HashTable,它的缺点是对hashCode映射为地址后如果出现重复地址,则会占用其他元素的位置。这样HashTable存储容量有限,而且不便于算法理解。本文介绍链地址法实现HashMap。
链地址法内部仍然有一个数组,但区别与开放地址法,该数组存储的是一个链表的引用。当根据hashCode计算出数组下表后,对元素的增删查改都是在该数组元素所指向的链表上完成的。这就解决了hashCode重复的问题。因为,当hashCode重复,多个元素对应同一个地址,但元素实际存储的位置在数组对应的链表上。所以相同hashCode的不同元素可以存储在同一位置。
下面是代码实现:
package org.lyk.interfaces; public interface IMap<K,V> { /** * 根据key值增加一个value,如果key重复,则新元素替换旧元素 * @param key * @param value */ public void put(K key, V value); /** * 根据key值移除value * @param key * @return */ public boolean remove(K key); public V get(K key); public boolean contains(K key); public void replace(K key, V value); }
package org.lyk.impl; import java.util.ArrayList; import org.lyk.interfaces.IMap; public class HashMap<K,V> implements IMap<K, V> { private class KeyValue { private K key; private V value; public KeyValue(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } } private int maxSize = 10; private Object[] table; public HashMap() { this.table = new Object[this.maxSize]; for(int i = 0; i < this.maxSize; i++) { this.table[i] = new java.util.ArrayList<KeyValue>(); } } @Override public void put(K key, V value) { int index = this.getIndex(key); KeyValue kv = this.find(key); if(kv == null) { ((java.util.List<KeyValue>)this.table[index]).add(new KeyValue(key, value)); } else { kv.setValue(value); } } @Override public boolean remove(K key) { int index = this.getIndex(key); java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index]; int listIndex = -1; for(KeyValue kv : kvs) { if(kv.key.equals(key)) { listIndex = kvs.indexOf(kv); } } if(listIndex != -1) { kvs.remove(listIndex); return true; } return false; } @Override public V get(K key) { KeyValue kv= this.find(key); if(kv != null) return kv.getValue(); else return null; } @Override public boolean contains(K key) { if(this.get(key) != null) return true; else return false; } @Override public void replace(K key, V value) { KeyValue kv = this.find(key); if(kv != null) { kv.setValue(value); } } private int getIndex(K key) { return Math.abs(key.hashCode())%this.maxSize; } private KeyValue find(K key) { int index = this.getIndex(key); java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index]; for(KeyValue kv : kvs) { if(kv.key.equals(key)) { return kv; } } return null; } }
以上是关于链地址法实现HashMap的主要内容,如果未能解决你的问题,请参考以下文章
HashMap1.8底层数据结构分析源代码解析1.7头插法如何形成环形链表