《java编程思想》:散列的原理

以实现一个简单的HashMap为例,详细讲解在code之中。

简单解释散列原理:

1.map中内建固定大小数组,但是数组并不保存key值本身,而是保存标识key的信息

2.通过key生成数组角标,对应位置存放LinkedList,list中存放的是键值对

3.如此,无论放入多少个键值对,数组大小都不必改变,当key值生成的角标值重复时,获取对应位置的list,向list中添加键值对即可

4.当调用get()方法时,只需遍历对应角标位置的list,而不用遍历所有的键值对信息,所以加快了查询速度。

5.注意,get()和put()中使用的计算散列值,也就是数组角标的公式一定要一致,保证计算所得的角标一致

/**
 * Created by Don9 on 2017/
 */
public class MyHashMap<K,V> extends AbstractMap<K,V>{
    /* 1.自定义数组大小 */
    static final int SIZE = 999;
    /* 2.创建内部数组,数组存放的是LinkedList,而list中存放的是想要存放的键值对 */
    LinkedList<MyEntry<K,V>>[] buckets = new LinkedList[999];
    /* 3.put方法,此方法返回key对应的曾经的oldValue */
    public V put(K key,V value){
        /* 4.先定义一个返回值 */
        V oldValue = null;
        /* 5.根据key计算出一个散列值,用于当作内置数组的下角标(
            此公式不固定,是自定义的,但是要保证结果稳定不变,同时不能大于数组size) */
        int index = Math.abs(key.hashCode()) % SIZE;
        /* 6.当index位置为空时,填充新的list */
        if(buckets[index]==null){
            buckets[index] = new LinkedList<MyEntry<K,V>>();
        }
        /* 7.获取index位置的list */
        LinkedList<MyEntry<K, V>> bucket = buckets[index];
        /* 8.MyEntry是自定义的Entry实现类,用于保存键值对,这个类也可以自定义,只要实现接口Entry即可,
            新建entry保存传入的键值对 */
        MyEntry<K, V> newMe = new MyEntry<K, V>(key,value);
        /* 9.定义一个found标记,用于记录是否替换完毕 */
        boolean found = false;
        ListIterator<MyEntry<K, V>> it = bucket.listIterator();
        /* 10.遍历当前位置的list */
        while(it.hasNext()){
            MyEntry<K, V> oldMe = it.next();
            /* 11.list中已经存在了当前key */
            if(oldMe.getKey().equals(key)){
                /* 12.获得oldValue值,用于返回 */
                oldValue = oldMe.getValue();
                /* 13.用新的entry替换老的 */
                it.set(newMe);
                /* 14.标记改为true,说明替换完毕 */
                found = true;
                /* 15.跳出 */
                break;
            }
        }
        /* 16.如果未替换完毕,也就是说key值在之前的list中不存在 */
        if(!found){
            /* 17.添加新的entry到list中 */
            bucket.add(newMe);
        }
        /* 18.返回oldValue */
        return oldValue;
    }

    /* 19.定义get查找方法 */
    public V get(Object key){
        /* 20.生成散列值,也就是数组角标,此处一定要和put方法中生成方式一致,保证相同的key生成相同的位置 */
        int index = Math.abs(key.hashCode()) % SIZE;
        /* 21.index位置为null,不存在key,返回null */
        if(buckets[index]==null){
            return null;
        }
        /* 22.index位置不为null,遍历查询,返回value */
        for(MyEntry<K,V> me:buckets[index]){
            if(me.getKey().equals(key)){
                return me.getValue();
            }
        }
        return null;
    }


    @Override
    public Set<Entry<K, V>> entrySet() {
        return null;
    }
}
原文地址:https://www.cnblogs.com/don9/p/6941298.html