基本概念
哈希表是一种特殊的数据结构,通过索引,能快速的查找到某个元素。
| put | get | |
|---|---|---|
| List | O(n) | O(n) |
| Balanced BST | O(logn) | O(logn) |
| Hash Table | O(1) | O(1) |
设计原理
通过哈希函数,将key映射到value上。
- Java 中哈希的实现
| Balanced BST | HashTable |
|---|---|
| TreeSet | HashSet |
| TreeMap | HashMap |
哈希函数 (hash function)
确定性,不可逆性。
输入任何二进制数据,输出整数。
在密码学也有广泛应用。
一个好的哈希函数,要在给定的输入范围内,尽可能少的发生碰撞;而且计算复杂度不能太高。
除余法(modulo division)
1
2
3
4// Java String hashcode
for (char c : str) {
hashCode = 31 * hashCode + c;
}平方取中法(mid-square)
- 基数转换法(radix transformation)
冲突解决(collision)
- 开散列(open hashing)
开辟一个数组
数组的每一个元素是一个链表的头结点的引用
通过Hash函数,计算key对应的index,将index相同的key-value插入到同 一个链表中 - 闭散列(closed hashing)
open addressing
开辟一个数组,一个位置只放一个key-value
通过Hash函数,计算key对应的index,将key-value放在相应的位置
如果这个位置已经有了元素,则查找其他合适的空位置放入
线性探查 (linear probing)
二次探查 (quadratic probing)
随机探查 (random probing)
双散列探查 (double hashing)
重哈希(rehashing)
当哈希表中的元素越来越多的时候,冲突的几率也就越来越高。为了提高查询的效率,就要对哈希表进行扩容。
负载因子(load factor) : 哈希表中的元素个数除以哈希表的容量。
哈希表检索的时间与负载因子有关, 当负载因子小于0.5时,大部分检索长度小于2; 当负载因子大于0.5时,性能急剧下降。这是一种空间换时间的方法。
重哈希就是调整哈希表的大小,并将元素重新摆放。
当哈希表过于稀疏,可以节省空间。
当哈希表过于稠密,可以加速查找。
实现
基本操作
查找
添加
删除
平均来说各操作的时间复杂度为O(1),但最坏情况会到O(n)。因为在添加的过程中会出现碰撞和重哈希的过程。
定义HashMap接口
1 | public interface Map { |
定义键值对
1 | public class Pair { |
使用open hashing解决collision
separate chaining方法
1 | class ListNode { |
使用closed hashing解决collision
linear probing 方法
1 | public class LPHashing implements Map{ |
Lintcode 相关练习
Count Characters
Strobogrammatic Number
two sum
Anagrams
Copy List with Random Pointer