哈希表(HashTable)
- 1. 相关概念
- 2. 哈希函数选择(常用)
- 3. 哈希冲突(常用)
- 开散列法/哈希桶法/链地址法:
- 4. Set接口及实现类
- 4.0 常用方法
- 4.1 HashSet
- 4.2 LinkedHashSet
- 4.3 TreeSet
- 4.4 例题
1. 相关概念
- 哈希函数:可通过该函数计算关键字的存储位置;
- 哈希冲突:不同关键字通过哈希函数计算出的存储位置一致;
2. 哈希函数选择(常用)
方法 | 介绍 |
---|---|
直接定制法 | 取关键字的某个线性函数计算散列地址:Hash(key)=A*key+B;简单、均匀,但需要事先知道关键字的分布情况,适合查找比较小且连续的情况 |
除数留余法 | 设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:Hash(key) = key% p(p<=m),将关键码转换成哈希地址 |
3. 哈希冲突(常用)
开散列法/哈希桶法/链地址法:
使用数组+链表的形式实现:
- 对关键字进行哈希映射,计算每个关键字的哈希地址,哈希地址一致的所有关键字处于同一个“桶”中;
- “桶”中所有元素以单链表的形式进行连接,链表头结点存储在哈希表中;
- “桶”中存放的是发生哈希冲突的元素;
如果哈希冲突比较严重,“桶”的大小会非常庞大,影响查找效率,所以可对其进行优化:
- 使用另一个哈希表实现“桶”或使用搜索树实现“桶”;
4. Set接口及实现类
- Set接口实现了Collection接口,用于存储无序、无重复的数据;
- HashSet、LinkedHashSet、TreeSet为Set接口的实现类;
- LinkedHashSet为HashSet的子类,使得遍历set时可按照元素插入顺序进行读取;
- HashSet线程不安全,为Set接口的主要实现类,可存储null值的key;
- TreeSet线程不安全,底层实现为红黑树,也就是平衡搜索树,元素必须为同一类型数据,之间可进行比较,因此TreeSet可进行定制排序;
4.0 常用方法
4.1 HashSet
- 无序性:指的是存储数据时并不按照底层数组的索引顺序进行存储,而是通过哈希值进行存储;
- 不可重复性:添加元素时会通过元素对应类型的equals方法和hashCode方法进行比较,查看是否重复,如果equals方法返回true则说明元素重复;
- 线程不安全,为Set接口的主要实现类,可存储null值的key;
- 元素插入操作:
1)首先通过元素x对应类的hashCode方法计算元素x的哈希值hashVal;
2)借助hashVal通过一定的算法计算元素x在哈希表中的哈希地址hashIndex:
查看hashIndex处是否已经存有元素:(1)如果没有,则直接将x存储在该位置;(2)如果存有元素,则依次与此哈希桶中的每个元素进行比较,遍历比较过程中,如果某已有元素与x的哈希值一样且equals方法返回true则说明有重复元素,添加失败;反之如果哈希值一样但equals方法返回false或哈希值不一样则继续遍历单链表,直到链尾则说明无重复元素,添加成功; - 要求:1)待添加元素所在类必须重写hashCode方法和equals方法;2)重写的hashCode方法和equals方法尽可能保证一致性:相等的对象必须具有相同的散列码;
4.2 LinkedHashSet
- 为HashSet的子类,在HashSet的基础上进行加强,将所有添加的元素按照添加顺序以链表形式连接起来,便于频繁遍历操作;
- 可存储null值的key;
- 每个元素存储时,同时维护两个引用,一个表示前驱结点,一个表示后继节点;
4.3 TreeSet
-
TreeSet线程不安全,底层实现为红黑树,也就是平衡搜索树,元素必须为同一类型数据,之间可进行比较,因此TreeSet可进行自然排序(java.lang.Comparable接口)或定制排序(java.util.Comparator接口);
-
自然排序下,TreeSet添加元素时,使用元素所在类中的compareTo()方法进行大小比较,如果返回值为0说明两元素内容相同;
-
定制排序下,TreeSet添加元素时,使用TreeSet对象实例化时传入的比较器Comparator中的compare()方法进行大小比较,如果返回值为0说明两元素内容相同;
4.4 例题
资料来源:尚硅谷