哈希表(Hash Table,也称散列表)是一种通过键(Key)直接访问内存存储位置的数据结构。它使用哈希函数将键映射到表中的位置,从而加快查找速度。
哈希表的核心思想是:通过一个函数(哈希函数)将任意大小的数据映射到固定大小的数据(通常是整数索引),这个整数作为数组的索引,从而可以直接访问到存储的值。
哈希函数是哈希表的核心,它将任意大小的输入(键)转换为固定大小的输出(哈希值)。一个好的哈希函数应该具备以下特点:
点击单元格查看详细信息
每个哈希表位置存储一个链表,所有哈希到同一位置的元素都存储在这个链表中。
当发生冲突时,按照某种探测序列寻找下一个空闲位置。
删除操作需要特殊处理,不能简单地将位置置空,否则会影响后续查找。常用的方法是使用标记(如"已删除"标记)而不是真正删除。
数据库使用哈希表实现索引,加快数据检索速度。例如,MySQL的MEMORY存储引擎使用哈希索引。
Redis、Memcached等缓存系统使用哈希表存储键值对,实现快速数据访问。哈希表的高效查找特性使其非常适合缓存场景。
编译器使用哈希表存储符号表,快速查找变量、函数等标识符的信息。哈希表可以高效处理大量标识符的查找和插入。
哈希函数在密码学中广泛应用,用于密码存储和验证。系统存储密码的哈希值而非明文密码,提高安全性。
哈希函数可以生成数据的唯一标识,用于数据去重、文件校验等场景。例如,Git使用SHA-1哈希作为提交ID。
哈希冲突是指不同的键经过哈希函数计算后得到相同的哈希值(索引)。解决哈希冲突的常用方法有:
哈希表的平均时间复杂度如下:
| 操作 | 平均情况 | 最坏情况 |
|---|---|---|
| 查找 | O(1) | O(n) |
| 插入 | O(1) | O(n) |
| 删除 | O(1) | O(n) |
最坏情况发生在所有键都哈希到同一位置时,此时哈希表退化为链表。
一个好的哈希函数应具备以下特性:
常用的哈希函数设计方法包括:除法哈希法、乘法哈希法、全域哈希法等。在实际应用中,应根据具体数据类型和场景选择合适的哈希函数。
| 特性 | 哈希表 | 平衡二叉搜索树 |
|---|---|---|
| 平均查找时间 | O(1) | O(log n) |
| 最坏查找时间 | O(n) | O(log n) |
| 有序遍历 | 不支持 | 支持 |
| 内存使用 | 通常更多 | 通常更少 |
| 实现复杂度 | 相对简单 | 相对复杂 |
选择哈希表还是平衡二叉搜索树取决于具体需求:如果需要快速查找且不需要有序遍历,哈希表是更好的选择;如果需要有序遍历或保证最坏情况性能,平衡二叉搜索树更合适。
哈希表需要扩容当负载因子(已存储元素数量与总容量的比值)超过某个阈值时,通常为0.7-0.75。扩容过程称为再哈希:
扩容操作的时间复杂度为O(n),但分摊到每次插入操作上,平均时间复杂度仍为O(1)。