【Java 数据结构与算法】-哈希表

作者:学Java的冬瓜
博客主页:☀冬瓜的主页
专栏:【Java 数据结构与算法】
分享:曾梦想仗剑走天涯,看一看世界的繁华。——许巍《曾经的你》
主要内容:哈希方法,哈希函数,哈希表,哈希冲突,负载因子,降低哈希冲突,解决哈希冲突。

在这里插入图片描述

文章目录

  • 一、什么是哈希表?
  • 二、哈希函数
    • 1、直接定制法
    • 2、除留取余法
  • 三、哈希冲突
    • 1、什么是负载因子?
    • 2、怎么降低哈希冲突?
    • 3、怎么解决哈希冲突?
      • @ 闭散列
      • @ 开散列(哈希桶 重点)

一、什么是哈希表?

  • 在顺序结构和平衡树中,想要查找一个元素,必须先经过多次比较,才能找到。但是在哈希表中不一样。
  • 哈希表是一种数据结构,通过哈希函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系(即这个关键码通过哈希函数计算可以得到元素的存储位置,所以速度极快),这个存储结构就是哈希表。

二、哈希函数

  • 为了避免哈希冲突,有两种哈希函数方法比较普遍。

1、直接定制法

  • 取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B
  • 优点:简单、均匀 ;缺点:需要事先知道关键字的分布情况
  • 使用场景:适合查找比较小且连续的情况
  • 面试题:【字符串中的第一个唯一字符】

2、除留取余法

  • 设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数:
    Hash(key) = key% p(p<=m),将关键码转换成哈希地址。

三、哈希冲突

1、什么是负载因子?

负载因子也可称为荷载因子。

负载因子 α = 哈希表中元素个数 / 哈希表的长度

哈希表的长度没有扩容之前是定长的,当哈希表中元素的个数增加时,负载因子α就会变大,那么越容易出现哈希冲突,所以我们应该严格控制负载因子的大小,在 Java 中,限制了负载因子最大为 0.75,当超过了这个值,就要进行扩容哈希表,重新哈希(重新将各个元素放在新的位置上)。

2、怎么降低哈希冲突?

<1> 使用合适的哈希函数
<2> 增加散列表的长度。当负载因子越来越大时,冲突率越来越高。如果想要降低冲突率,就是要降低负载因子,那就增加散列表的长度。

【Java 数据结构与算法】-哈希表_第1张图片

3、怎么解决哈希冲突?

@ 闭散列

  • 闭散列又称开放地址法

开放地址法具体操作有以下两种:

集合:{17459}

线性探测

通过哈希函数获取待插入元素在哈希表中的位置
如果该位置中没有元素则直接插入新元素;
如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素。

【Java 数据结构与算法】-哈希表_第2张图片

二次探测:

首先H0经过key%m得到,然后如果冲突,就再次计算,直到算出不冲突的值。

【Java 数据结构与算法】-哈希表_第3张图片

@ 开散列(哈希桶 重点)

  • 开散列又称链地址法,哈希桶。
集合:{17459}
要插入:344484

【Java 数据结构与算法】-哈希表_第4张图片

  • 插入操作:JDK1.7之前,采用头插法;JDK1.8开始,使用尾插法。
  • 哈希表使用:数组+链表的形式,当链表长度超过 8且数组长度超过 64时,链表会变成红黑树
  • 那么就出现一个问题,当链表长度超过 8且数组长度超过 64,二者都满足时,链表才会变成红黑树。那有没有可能链表长度很长,但数组长度不超过64呢?
    没有可能!因为链表长度很长时,代表哈希冲突率很高了,那要降低哈希冲突,就需要降低负载因子(Java的系统库限制了负载因子为0.75),负载因子和数组长度成反比,那么就是得增大数组长度,这样当链表长度超过8,数组长度超过64时,链表就变成了红黑树。这样就把数组长度和链表长度联系起来了。
  • 哈希表查找时间复杂度:近似log(1)
    当链表长度比较短时,近似O(1)
    链表长度变长时,会通过加长数组来降低冲突率,从而使链表长度降低(数组长度增长后原来的链表会被打散),也近似O(1)
    当链表长度超过8,数组长度超过64时,复杂度为O(logn)。
    其实复杂度随着数组长度变化,链表长度的变化而变化。但是可以近似看成O(1)。

你可能感兴趣的:(【Java,数据结构与算法理解及刷题】,java,散列表,哈希算法,数据结构)