链地址法实现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);
    
}
IMap
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

 

以上是关于链地址法实现HashMap的主要内容,如果未能解决你的问题,请参考以下文章

HashMap从源码分析数据结构

JDK1.8中对hashmap的优化

理解HashMap底层数据结构

HashMap1.8底层数据结构分析源代码解析1.7头插法如何形成环形链表

HashMap1.8底层数据结构分析源代码解析1.7头插法如何形成环形链表

HashMap1.8底层数据结构分析源代码解析1.7头插法如何形成环形链表