1. 什么是哈希表

哈希表(Hash Table)是一种数据结构,它可以快速地在大量数据中查找、插入和删除时数据。哈希表通过使用哈希函数将键(Key)映射到一个位置,然后在该位置存储或查找数据。

哈希函数的作用是,将键转换为一个整数,这个整数通常称为哈希值(Hash Value)。哈希表的范围通常与哈希表的大小相同。当我们插入或查找数据时,首先计算键的哈希值,然后根据哈希值在哈希表中定位数据。

这里有一个简单的例子来说明哈希表的工作原理:
    假设我们有一个哈希表,大小为5,哈希函数为key mod 5。现在我们要插入键值分别为1、3、8和11的数据。
    首先,我们计算每个键的哈希值:1 mod 5 = 1,3 mod 5 = 3,8 mod 5 = 3,11 mod 5 = 1。然后,我们根据哈希值在哈希表中定位数据。键值为1和11的数据被映射到哈希表的第2个位置(下标从0开始),键值为3和8的数据被映射到哈希表的第4个位置。
    由于键值为1和11被映射到同一个位置,因此发生了哈希冲突。此时,我们可以采用链地址法来解决冲突,在第2个位置建立一个链表,将这两个数据依次存储在链表中。


最终,哈希表中的数据存储情况如下:
```
0: 空
1: [1] -> [11]
2: 空
3: [3] -> [8]
4: 空
```


    当我们查找键值为8的数据时,首先计算它的哈希值:8 mod 5 = 3。然后根据哈希值在哈希表中定位数据,在第4个位置找到了一个链表。最后,在链表中查找键值为8的数据,并返回结果。

由于不同的键可能被映射到同一个位置,因此需要采取一些措施来解决哈希冲突。

2. 什么是哈希冲突

哈希冲突(Hash Collision)是指在使用哈希表存储数据时,两个或多个不同的键(Key)被哈希函数映射到同一个位置的情况。这种情况会导致数据的存储和查找变得复杂,因此需要采取一些措施来解决哈希冲突。

3. 解决哈希冲突的方法

1、开放地址法(Open Addressing)

是一种解决哈希冲突的方法,它的基本思想是,当发生哈希冲突时,按照某种规则寻找下一个空闲的位置来存储数据。

常用的开放地址法有线性探测法、二次探测法和双重哈希法。

(1)线性探测法

是指当发生哈希冲突时,从当前位置开始,依次向后查找下一个空闲的位置,或查遍全表。

例如:
    假设我们有一个哈希表,大小为5,哈希函数为key mod 5。当我们插入键值为1、6和11的数据时,它们都会被映射到哈希表的第2个位置(1 mod 5 = 6 mod 5 = 11 mod 5 = 1)。此时,我们可以采用线性探测法来解决冲突。
    首先将键值为1的数据存储在第2个位置,然后从第2个位置开始,依次向后查找下一个空闲的位置。最终,我们找到了第3个位置,并将键值为6的数据存储在那里。同样地,我们再次从第2个位置开始查找,并在第4个位置找到了一个空闲的位置,将键值为11的数据存储在那里。


''
0: 空
1: [1]
2: [6]
3: [11]
4: 空
''

使用线性探测法解决哈希冲突时,查找、插入和删除操作的时间复杂度与哈希表的装载因子成正比。因此,在设计哈希表时,应尽量选择合适的哈希函数和哈希表大小,并合理控制装载因子,以减少冲突的发生。

(2)二次探测法

是指当发生哈希冲突时,从当前位置开始,按照二次函数的规律查找下一个空闲的位置。

这里有一个简单的例子来说明二次探测法的工作原理。
    假设我们有一个哈希表,大小为5,哈希函数为key mod 5。现在我们要插入键值分别为1、3、8和11的数据。我们采用二次探测法来解决哈希冲突。
    首先,我们计算每个键的哈希值:1 mod 5 = 1,3 mod 5 = 3,8 mod 5 = 3,11 mod 5 = 1。然后,我们根据哈希值在哈希表中定位数据。键值为1和11的数据被映射到哈希表的第2个位置(下标从0开始),键值为3和8的数据被映射到哈希表的第4个位置。
    由于键值为1和11被映射到同一个位置,因此发生了哈希冲突。此时,我们可以采用二次探测法来解决冲突,从第2个位置开始,按照二次函数的规律查找下一个空闲的位置。最终,我们找到了第4个位置,并将键值为11的数据存储在那里。
    同样地,由于键值为3和8被映射到同一个位置,因此也发生了哈希冲突。我们采用同样的方法解决冲突,从第4个位置开始,按照二次函数的规律查找下一个空闲的位置。最终,我们找到了第0个位置,并将键值为8的数据存储在那里。

最终,哈希表中的数据存储情况如下:
```
0: [8]
1: [1]
2: 空
3: [3]
4: [11]
```


    当我们查找键值为8的数据时,首先计算它的哈希值:8 mod 5 = 3。然后根据哈希值在哈希表中定位数据,在第4个位置发现没有数据。此时,我们按照二次探测法的规则继续查找,并在第0个位置找到了键值为8的数据。

使用二次探测法解决哈希冲突时,查找、插入和删除操作的时间复杂度与哈希表的装载因子成正比。因此,在设计哈希表时,应尽量选择合适的哈希函数和哈希表大小,并合理控制装载因子,以减少冲突的发生。

(3)双重哈希法

是指当发生哈希冲突时,使用另一个哈希函数计算出下一个空闲的位置。

这里有一个简单的例子来说明双重哈希法的工作原理。
    假设我们有一个哈希表,大小为5,第一个哈希函数为h1(key) = key mod 5,第二个哈希函数为h2(key) = 3 - (key mod 3)。现在我们要插入键值分别为1、3、8和11的数据。我们采用双重哈希法来解决哈希冲突。    首先,我们计算每个键的哈希值:h1(1) = 1 mod 5 = 1,h1(3) = 3 mod 5 = 3,h1(8) = 8 mod 5 = 3,h1(11) = 11 mod 5 = 1。然后,我们根据哈希值在哈希表中定位数据。键值为1和11的数据被映射到哈希表的第2个位置(下标从0开始),键值为3和8的数据被映射到哈希表的第4个位置。
    由于键值为1和11被映射到同一个位置,因此发生了哈希冲突。此时,我们可以采用双重哈希法来解决冲突,使用第二个哈希函数计算出下一个空闲的位置:(1 + h2(11)) mod 5 = (1 + (3 - (11 mod 3))) mod 5 = (1 + (3 - 2)) mod 5 = (2) mod 5 = 2。最终,我们找到了第3个位置,并将键值为11的数据存储在那里。
    同样地,由于键值为3和8被映射到同一个位置,因此也发生了哈希冲突。我们采用同样的方法解决冲突,使用第二个哈希函数计算出下一个空闲的位置:(3 + h2(8)) mod 5 = (3 + (3 - (8 mod 3))) mod 5 = (6) mod 5 = 1。由于第2个位置已经被占用,因此我们继续计算下一个空闲的位置:(3 + h2(8) * h2(8)) mod 5 = (9) mod 5 =4。最终,我们找到了第0个位置,并将键值为8的数据存储在那里。

最终,哈希表中的数据存储情况如下:
```
0: [8]
1: [1]
2: [11]
3: [3]
4: 空
```

当我们查找键值为8的数据时,首先计算它的哈希值:h1(8) = 8 mod

2、链地址法

链地址法是一种处理哈希冲突的方法,它是将所有散列到同一个地址的数据项存储在一个单链表中。这样,当查找某个数据项时,只需要在对应的链表中进行搜索即可。例如,HashMap 在解决存储对象存在 hash 冲突的问题时,采用的就是链地址法,将相同 hash 值的对象以链表的形式进行存储。

3、再哈希法

在发生冲突的时候,再用另一个哈希函数算出哈希值,直到算出的哈希值不同为止。

4、建立公共溢出区

在创建哈希表的同时,再额外创建一个公共溢出区,专门用来存放发生哈希冲突的元素。查找时,先从哈希表查,查不到再去公共溢出区查。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐