浅析java8中HashMap的结构

来源:互联网 发布:网络在线电台广播收听 编辑:程序博客网 时间:2024/06/10 19:54

HashMap中涉及的部分数据结构

数组
数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难

链表

链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易

哈希表之拉链法

哈希表(Hash table,也叫散列表),是根据关键码值(Key-value)而直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录,有点类似于数组,并且能在O(1)(冲突情况另算)下查找到元素。这个映射函数叫做散列函数,存放记录的数组叫做散列表
需要注意的是,在 Java 8 中如果 hash 值相同的 key 数量大于指定值(默认是8)时使用平衡树来代替链表,这会将get()方法的性能从O(n)提高到O(logn)。
而拉链法其实是hashtable查找中一种解决冲突的查询方法,也是最常用来实现hashtable的一种方法。
用拉链法实现的hashtable还可以理解为一个链表的数组,因为该结构就是通过数组+链表的组合来实现的,数组的每个元素中都存放一个链表的头结点。如下图所示:

拉链法的具体实现是:将所有关键字为同义词的结点链接在同一个单链表中。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数组t[0..m-1]。凡是散列地址为i的结点,均插入到以t为头指针的单链表中。t中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。举个栗子:

上图是一个长度为16的数组,每个元素存储着一个链表的头结点,元素存储在数组中的位置(index)是通过hash(key)%len获得的,也就是用元素key的哈希值对数组长度取模得到的。例如数组索引为12的这条记录,12%16=12,28%16=12,108%16=12.140%16=12。所以12、28、108、140都存储在数组索引为12的位置。
HashMap其实也是一个线性的数组,就如刚刚所言,他的实现可以理解为一个“链表的数组”。而且HashMap里面实现了一个Node作为一个基础Bean,用来保存HashMap中的内容。该Bean中重要的属性有hash、key、value、next。部分源码如下:
static class Node<K,V> implements Map.Entry<K,V> {        final int hash;        final K key;        V value;        Node<K,V> next;        Node(int hash, K key, V value, Node<K,V> next) {            this.hash = hash;            this.key = key;            this.value = value;            this.next = next;        }        public final K getKey()        { return key; }        public final V getValue()      { return value; }        public final String toString() { return key + "=" + value; }        public final int hashCode() {            return Objects.hashCode(key) ^ Objects.hashCode(value);        }        public final V setValue(V newValue) {            V oldValue = value;            value = newValue;            return oldValue;        }        public final boolean equals(Object o) {            if (o == this)                return true;            if (o instanceof Map.Entry) {                Map.Entry<?,?> e = (Map.Entry<?,?>)o;                if (Objects.equals(key, e.getKey()) &&                    Objects.equals(value, e.getValue()))                    return true;            }            return false;        }    }


原创粉丝点击