一、哈希冲突
1. 什么是哈希冲突
在 Java 中,当使用哈希表(如 HashMap、HashSet 等)存储数据时,会通过哈希函数计算键(Key)的哈希值,然后根据这个哈希值来确定数据在哈希表中的存储位置。哈希冲突指的是,不同的键通过哈希函数计算后得到了相同的哈希值,从而映射到了哈希表中的同一个位置。
2. 产生哈希冲突的原因
哈希函数通常是将一个大范围的输入映射到一个相对小范围的输出,而输入的可能性远远多于输出的可能性,所以不可避免地会出现多个不同输入对应同一个输出的情况,也就是哈希冲突。例如,在 HashMap 中,哈希表的初始容量是有限的,当存储的数据增多时,发生哈希冲突的概率就会增加。
3. 解决哈希冲突的常见方法
3.1 链地址法(拉链法)
Java 中的 HashMap 就是使用链地址法来解决哈希冲突的。当发生哈希冲突时,会在哈希表的同一个位置形成一个链表(JDK 8 及以后,当链表长度超过 8 且数组长度大于 64 时,链表会转换为红黑树),将冲突的元素依次添加到链表中。查找元素时,先通过哈希值找到对应的链表,然后在链表中依次查找目标元素。
以下是一个简单的链地址法示例代码:
import java.util.LinkedList;
class HashTable {
private LinkedList<Integer>[] table;
private int size;
public HashTable(int size) {
this.size = size;
table = new LinkedList[size];
for (int i = 0; i < size; i++) {
table[i] = new LinkedList<>();
}
}
private int hash(int key) {
return key % size;
}
public void insert(int key) {
int index = hash(key);
table[index].add(key);
}
public boolean search(int key) {
int index = hash(key);
return table[index].contains(key);
}
}
public class HashCollisionExample {
public static void main(String[] args) {
HashTable hashTable = new HashTable(5);
hashTable.insert(1);
hashTable.insert(6); // 与 1 发生哈希冲突
System.out.println(hashTable.search(6)); // 输出: true
}
}
3.2 开放地址法
开放地址法是指当发生哈希冲突时,通过一定的规则(如线性探测、二次探测等)在哈希表中寻找下一个可用的位置。例如,线性探测就是在冲突位置的基础上依次向后查找,直到找到一个空位置。
二、扩容机制
1. 为什么需要扩容
随着哈希表中存储的元素不断增加,哈希冲突的概率也会越来越高,这会导致哈希表的性能下降,查找、插入和删除操作的时间复杂度可能会接近 O(n)O(n)O(n)。为了保证哈希表的性能,当哈希表中的元素数量达到一定阈值时,就需要对哈希表进行扩容。
2. HashMap 的扩容机制
2.1 扩容的触发条件
在 HashMap 中,有两个重要的参数:容量(capacity)和负载因子(loadFactor)。容量指的是哈希表中数组的长度,负载因子是一个介于 0 到 1 之间的浮点数,默认值为 0.75。当哈希表中的元素数量(size)超过 capacity * loadFactor 时,就会触发扩容操作。
2.2 扩容的过程
- 创建新数组:将原数组的容量扩大为原来的 2 倍。
- 重新哈希:遍历原数组中的每个元素,重新计算它们在新数组中的位置,并将元素插入到新数组中。
以下是 HashMap 扩容的简单示例代码(模拟部分原理):
import java.util.HashMap;
public class HashMapResizeExample {
public static void main(String[] args) {
HashMap<Integer, String> map = new HashMap<>(2);
map.put(1, "apple");
map.put(2, "banana");
map.put(3, "cherry"); // 触发扩容
System.out.println(map.size()); // 输出: 3
}
}
3. 扩容对性能的影响
扩容操作涉及到创建新数组和重新哈希,是一个比较耗时的操作,时间复杂度为 O(n)O(n)O(n)。因此,在使用哈希表时,尽量预估好元素的数量,合理设置初始容量,以减少扩容的次数,提高性能。
1576

被折叠的 条评论
为什么被折叠?



