哈希表(HashTable)

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 例题

在这里插入图片描述
资料来源:尚硅谷

猜你喜欢

转载自blog.csdn.net/qq_43665602/article/details/130144974
今日推荐