zoukankan      html  css  js  c++  java
  • 《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;
        }
    }
  • 相关阅读:
    vue ui 没反应
    vue脚手架安装教程
    DOS命令如何进入指定文件夹
    python-格式化(%,format,f-string)输出+输入
    Python基础-列表、元组、字典、字符串(精简解析)
    python中的lambda函数用法
    初识JAVA
    关于继承、封装、多态、抽象和接口(Java)
    Python中单下划线和双下划线
    Postgresql 创建SEQUENCE,Springboot中使用KeyHolder
  • 原文地址:https://www.cnblogs.com/don9/p/6941298.html
Copyright © 2011-2022 走看看