集合-HashMap

该文章的实践内容来自how2java网站,集合的学习篇章

1.概念:

     HashMap是以哈希表作为底层数据结构,以一组键值对作为存储单元的Map接口的实现类。

     其主要特点是,容器内的元素不以添加顺序排序,不可以用NULL作为键,但是可以用NULL作为值,非线程安全。

 

2.原理:

     当向HashMap中添加元素时,首先需要添加一个键(key),然后添加一个值(value)。键作为值的索引,在之后查找value时提供位置。而键在添加时,会用hashCode方法获取键的hash码,根据这个hash码按照一定规则添加到相应位置中(可以参考HashSet的存放)。但是尽管是不同的对象,在经过hashCode获得的hash值也有可能是相同的,或者在HashMap中存放散列单元相同。这时就会在确定hash值之后,调用键的equals方法来判断是否为同一对象。如果是,就替换该键对应的值。如果不是,则在该位置添加一个链表,把有相同hash值的不同对象的键存放在其中。

        注:键的存储与HashSet类似

 

3.简单的实现

     (1)用LinkedList数组作为底层数据结构,实现Entry作为键值对保存单元

 

private LinkedList<Entry>[] lArray = new LinkedList[2000];

 

     

public class Entry {

    public Entry(Object key,Object value){
        super();
        this.key = key;
        this.value = value;
    }
    private Object key;
    private Object value;

    public Object getValue(){
        return this.value;
    }

    public Object getKey(){
        return this.key;
    }

    public void setKey(Object key){
        this.key = key;
    }

    public  void setValue(Object value){
        this.value = value;
    }

    @Override
    public String toString(){
        return "[key="+key+",value="+value+"]";
    }

}

 

 

 

(2)首先需要实现一个简单的hashCode方法,来获取字符串的hash值

public static int hashcode(String str){
        int hcode = 0;
        for (int i = 0; i < str.length(); i++) {
            hcode = hcode + str.charAt(i)*(str.length()-1);
        }
        return hcode = hcode%2000;
    }

 注:这里在最后返回的值是模2000是为了让不同的字符串的哈希值都在2000以内,这样就会有大量重复的哈希值。在实现HashMap时,遇到相同hash值,就建立一个链表将其值存入其中

 

 (3)实现put方法

public void put(String key,Object value){
        //获取键的哈希值
        int hcode = hashcode(key);
        //判断该哈希值对应的存储位置是否有存储
        LinkedList<Entry> ll = lArray[hcode];
        if(null == ll){
            //新建一个链表存储在该位置,并将键值对保存在链表中
            ll = new LinkedList<>();
            lArray[hcode] = ll;
        }
        //判断该key是否已经有对应的键值对
        boolean found = false;
        for(Entry entry:ll){
            if(key.equals(entry.getKey())){
                entry.setValue(value);
                found = true;
                break;
            }
        }
        if(!found){
            Entry entry = new Entry(key,value);
            ll.add(entry);
        }
    }

(4)实现get方法

public Object get(String key){
        //获取key的哈希值
        int hcode = hashcode(key);
        LinkedList<Entry> ll = lArray[hcode];
        if(null == ll){
            return null;
        }else{
            for (Entry e:ll){
                if(key.equals(e.getKey()))
                    return e.getValue();
            }
            return null;
        }
    }

(5)最后用ArrayList和MyHashMap存储了100000个对象来测试两者查询所用时间差

 ArrayList<Hero> hl = new ArrayList<>();

        ArrayList<Hero> al = new ArrayList<>();
        MyHashMap mhm = new MyHashMap();
        for (int i = 0; i < 100000; i++) {
            Random rand = new Random( System.currentTimeMillis()+i);
            StringBuffer sb = new StringBuffer();
            sb.append("hero-");
            sb.append(rand.nextInt(9));
            sb.append(rand.nextInt(9));
            sb.append(rand.nextInt(9));
            sb.append(rand.nextInt(9));

            Hero hero = new Hero(sb.toString(),i);
            al.add(hero);
            //mhm.put(sb.toString(),hero);
        }

        for(Hero h:al){
            List<Hero> list = (List<Hero>)mhm.get(h.getName());
            if(null == list){
                list = new ArrayList<Hero>();
                mhm.put(h.getName(),list);
            }
            list.add(h);
        }

        long start = System.currentTimeMillis();
        for (int i = 0; i < al.size(); i++) {
            Hero h = al.get(i);
            String name = h.getName();
            if(name.equals("hero-5555")){
                hl.add(h);
            }
        }
        long end = System.currentTimeMillis();

        long elapsed = end -start;

        System.out.println("ArrayList列表中共有"+al.size()+"个对象");
        System.out.println("用for循环查找到了"+hl.size()+"个名字叫hero-5555的对象");
        System.out.println("耗时:"+elapsed);



        start = System.currentTimeMillis();
        List<Hero> hlist = (List<Hero>) mhm.get("hero-5555");
        end = System.currentTimeMillis();
        elapsed = end - start;
        System.out.println("用MyHashMap查找到了"+hlist.size()+"个名字叫hero-5555的对象");
        System.out.println("耗时:"+elapsed);

最后的运行结果是:

ArrayList列表中共有100000个对象
用for循环查找到了15个名字叫hero-5555的对象
耗时:7
用MyHashMap查找到了15个名字叫hero-5555的对象
耗时:0

可以看出,用MyHashMap查询时间比用一般查询ArrayList的方法要快,这里可以添加更多的对象来测试时间差

ArrayList列表中共有1000000个对象
用for循环查找到了139个名字叫hero-5555的对象
耗时:21
用MyHashMap查找到了139个名字叫hero-5555的对象
耗时:0

 

posted @ 2019-03-18 20:16  胡叁安  阅读(210)  评论(0编辑  收藏  举报