今天听课有个疑问,哈希表建表遇到冲突,解决冲突时是模表长还是小于表长的最大质数?又或者是两种都可以吗?
在解决哈希冲突时,通常使用小于表长的最大质数作为模数。这是因为使用模表长作为模数可能会导致哈希值分布不均匀,从而增加冲突的概率。而使用小于表长的最大质数作为模数可以更好地保证哈希值的均匀分布,从而减少冲突的概率。
都可以,比如我们用双重散列的话表长可以小于或等于最大质数就可以解决,而用其他链表之类的就不用
题目来源:
牛客网:字节跳动后端一面面试经验
CSDN:字节跳动后端开发实习面试一
牛客网:字节跳动一面二面凉经
牛客网:字节跳动后台开发实习三面
牛客网:字节跳动(上海)后端开发实习一面二面
知识点总结:
GitHub大佬总结
哈希表建表遇到冲突时,可以使用两种方法解决冲突:一种是使用模表长,一种是使用小于表长的最大质数。两种方法都可以,但通常建议使用小于表长的最大质数。
对于哈希表建表遇到冲突的情况,可以采用开放地址法和链地址法两种解决方法。其中,开放地址法又包括线性探测、二次探测和再哈希法等,链地址法则是指将散列到同一地址的键值放在一个链表中,实现方式为散列表的每个槽都是一个指向链表的头指针。
具体实现过程如下所示:
在哈希表中,每个键值都通过散列函数映射到一个具体的槽中,如果散列结果与其他键值映射到同一槽中,则产生了冲突。
对于开放地址法,可以采用线性探测法解决冲突。如果槽i已经被占用,则检查下一个槽(i+1)是否空闲,如果不空闲,则继续检查(i+2)、(i+3)...... 如果该过程将要查找的下一个位置已经越过哈希表的末尾,就从头开始重新查找。这样可以完成冲突的解决。
对于链地址法,可以将散列到同一地址的键值放在一个链表中,实现方式为散列表的每个槽都是一个指向链表的头指针。当发生冲突时,在该槽的链表上添加新的节点即可。
在选择哈希表建表遇到冲突的解决方法时,应该考虑两种方法的优缺点。一般来说,小于表长的最大质数可以减少哈希表中的冲突,从而提高查询效率。而模表长的方法通常更容易实现,但需要耗费更多的存储空间。因此,在实际开发中可以根据具体情况来选择不同的解决方法。
代码示例:(以使用小于表长的最大质数解决冲突为例)
int H(int k, int length){
int x;
x = k % length; //除留余数法 length为小于表长的最大质数
return x;
}
int InitHashTable(int ht[], int x, int length){
int i = H(x, length);
if (ht[i] == -1){
ht[i] = x;
return 0;
}else{
int j = i;
while (ht[i] != -1 && i != (j - 1 + length) % length){
i = (i + 1) % length;
}
if (i == (j - 1 + length) % length){
return -1;
}else{
ht[i] = x;
return 0;
}
}
}
在以上代码中,H函数是哈希函数,接受一个键值和表长作为参数,返回它在哈希表中的地址。InitHashTable函数是向哈希表中插入一个键值。如果该键值的地址已经被占用,则使用线性探测法找到开放地址,直到找到一个空闲地址为止。