哈希表是我们经常频繁使用的数据结构,所以它的知识点比较重要,如HashMap啊,就是哈希表结构,哈希表的底层是数组+链表结构的,非常之聪明,两者优点结合,数组查询快,链表增删快,并且hash采用算法分析定位地址,而不用再像数组一样需要遍历。
哈希表为什么采用数组+链表的结构呢?
答:通过一定算法计算出来的数字就可以对应数组下标找到对应位置,假如现在计算完的数字是0需要定位到0坐标上,然后又有一个数据需要存储,计算完之后位置还是0,那现在怎么办呢,那也不能覆盖把,这种问题的出现也叫哈希碰撞,那现在解决办法就是加链表,当发现计算完的位置是一样的就存储在一连串的链表里就能实现。
我就不瞎巴巴了,还是上官方介绍哈希表的介绍把
1.哈希表的介绍
哈希表(hash table,也叫散列表)是根据关键码值(key,value)而直接进行访问的数据结构。也就是说它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度,这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表可以提供快速的插入和查找工作,哈希表运算的非常快,而且编程实现也比较容易。哈希表是数组和链表结构
记录的存储位置=f(关键字),这里的对应关系f称为散列函数,又称为哈希(哈希函数),采用散列技术将记录存储在一块连续的存储空间中,这块连续存储空间称为散列表或哈希表
--视频资料介绍图片
2.哈希冲突
由于存储空间有限,hash计算以后可能不同的关键字映射到同一个哈希地址上,这种现象称之为哈希冲突,比如h(16)=16%11=5,h(27)=27%11=5,两个哈希地址就冲突了
--视频资料介绍图片
hash冲突是不可避免的,要解决hash冲突需要以下几种方式
3.开放地址法
3.1 线性探查(Linear Probing)
哈希冲突解决策略:开放寻址法(将所有的元素都存放在哈希表内的数组中,不使用额外的数据结构)
开放寻址法最简单的一种实现就是线性探查,步骤如下:
- 当插入新的元素时,使用哈希函数在hash表中定位元素位置;
- 检查哈希表中该位置是否已经存在元素,如果该位置为空,则插入并返回,否则转向步骤3
- 如果该位置为i,则检查i+1是否为空,如果已被占用,则检查i+2,以此类推,直到找到一个内容为空的位置。
视频资料图
线性探查(Linear Probing)方式虽然简单,但并不是解决冲突的最好的策略,因为会导致同类hash的聚集,这导致搜索hash表时冲突依然存在,例如上图例子中的哈希表,如果我们要访问Edward的信息,因为Edward的社保号是111-00-1235 哈希为1235,然而我们在1235找到的位置是Bob,所以再搜索1236,找到的确是Danny,以此类推才能找到最终答案,所以在查找的时候也会出现冲突的。
开放地址法的线性探测缺点就是,数据项聚集,越来越大,越到后面找到的空位插入数据项需要时间越多。
你已经猜到了,一个知识点第一个讲到的总是有缺陷,需要弥补的,那么二次探查和二度哈希出现在江湖。
3.2 二次探查(Quadratic Probing)
一种改进的方式为二次探查(Quadratic Probing),即每次检查位置空间的步长为平方倍数,也就是说,如果位置s被占用,则首先检查s+1的平方,然后检查s-1的平方,s+2的平方,s-2的平方,依次类推而不是像线性探查那样s+1,s+2.....方式增长,尽管如此,二次探查同样也会导致同类哈希聚集问题。
3.3 二度哈希(Rehashing)/双重哈希(Double Hashing)
啊呀呀,看hashmap看的脑瓜子疼啊,下次在梳理二度哈希链地址法等等