哈希表

哈希表:

面试中出场频率很高,工作中的出场频率也很高。
  1. 哈希表是基于数组演化而来,哈希表高效的秘密就在于数组的随机访问能力。哈希是用空间换时间。
  2. 针对输入的每个数字(key)都要进行一个数学运算的变换,把key经过一定的数学变换转成下标的过程,称为“哈希函数”/“散列函数”。哈希函数有一个重要特点:两个相同的key,计算得到的hash值一定相同。
  3. 哈希函数:key % 数组长度 = 下标的值
  4. 如果两个不同的key,通过哈希函数计算之后得到了相同的hash值,此时这种情况称为“哈希冲突”/“哈希碰撞”。

那么要如何处理哈希冲突?

  1. 尽量避免(降低冲突概率):选择更合适的hash函数。
    例如:如果把数组长度设定为素数,那么冲突改路就会降低不少。

    负载因子:哈希表中保存的元素个数 / 数组的长度。
    负载因子越小,冲突概率就越小。

  2. 正面应对(当冲突了之后通过一定的方式解决冲突)
    a). 闭散列:发现冲突之后,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么就在当前冲突位置周围找到一个空闲位置来插入元素。

    • 线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。
    • 二次探测:从发生冲突的位置开始,以2的次方进行探测,直到找到下一个空位置为止。

    b). 开散列/哈希桶:首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶的元素通过一个单链表链接起来,个链表的头结点存储在哈希表中。

    通俗的说:开散列的数组中的每个节点相当于一个链表的头结点,当出现hash冲突的时候就把新的元素插入到链表中。

无论是第一种方式还是第二种方式,当哈希冲突比较严重的时候,插入查找删除的效率仍然会很低。

如果冲突变得特别严重:

  1. 扩容(降低负载因子)成本比较高(不太推荐)。
  2. 针对开散列来说(链表),把链表替换成更高效的数据结构。比如二叉搜索树或者哈希表。

哈希函数一般如何来计算呢?

  1. 如果key为整数,hash值计算方式主要就是通过除留余数的方式,一般会搭配一些其他的数学。
  2. 如果key为字符串,如何计算hash值呢?
    md5 sha1 常用的字符串哈希算法。
    md5 的重要特点
    1.无论输入的字符串有多长,最终得到的md5值都是固定长度的。
    2.如果有两个字符串,大部分内容都相同,只有某个字符不相同,此时计算生成的md5值也会差别很大。(这一点就决定了md5算出的hash值最终冲突概率比较小)
    3.通过字符串来计算hash值,很高效,但是反之不行。(给定md5值,找出某个字符串的值是这个md5,这个计算量非常巨大,理论上是不可行的)。
    sha1也同样具备

哈希表就是HashMap/HashSet的底层实现。

Java中计算哈希值实际上是调用的类的 hashCode 方法,进行 key 的相等性比较是调用 key 的 equals 方法。所以如果要用自定义类作为 HashMap 的 key 或者 HashSet 的值,必须覆写 hashCodeequals 方
,而且要做到 equals 相等的对象,hashCode 一定是一致的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值