完全散列适用于静态关键字集合的零冲突o(1)查询,通过两层全域散列实现:第一层将键映射到主桶,第二层为冲突桶独立构造无冲突散列函数,确保查询严格两次哈希+一次比对。

在需要零冲突、确定性O(1)查询的静态关键字集合场景中,比如编译器关键字表、嵌入式设备只读配置项索引、DNS根域固定TLD列表查找,必须用完全散列避免任何链地址或开放寻址带来的最坏情况退化。
第一层哈希:构建主散列表
选取质数m作为第一层桶数量,满足m ≥ n(n为关键字总数),用全域散列族h₁(k) = ((a·k + b) mod p) mod m构造主哈希函数,其中p是大于等于最大关键字值的质数,a、b随机选取且1 ≤ a
将全部n个关键字k₁…kₙ依次计算h₁(kᵢ),填入长度为m的数组T,每个位置T[j]存储落在该桶内的关键字子集Sⱼ。
这一步不能跳过冲突检测——若某桶Sⱼ中元素数|Sⱼ| > 1,说明该桶需第二层哈希;若|Sⱼ| = 0或1,直接存入即可,无需二级结构。
第二层哈希:为每个非空桶独立设计无冲突函数
对每个|Sⱼ| > 1的桶Sⱼ,执行以下步骤:
① 设s = |Sⱼ|,取最小质数mⱼ满足mⱼ ≥ s²;
② 随机选取aⱼ, bⱼ ∈ {0, 1, …, mⱼ−1},定义h₂ⱼ(k) = ((aⱼ·k + bⱼ) mod pⱼ) mod mⱼ,其中pⱼ是大于Sⱼ中最大关键字的质数;
③ 计算所有k ∈ Sⱼ的h₂ⱼ(k),检查是否产生冲突;若存在i ≠ l使h₂ⱼ(kᵢ) = h₂ⱼ(kₗ),则丢弃当前(aⱼ,bⱼ),重新随机选取并重试;
④ 一旦找到无冲突的(aⱼ,bⱼ),将Sⱼ中每个k映射到二级表Tⱼ的索引h₂ⱼ(k),并在Tⱼ[h₂ⱼ(k)]处存入k对应的数据(如值、指针等);【注意:mⱼ必须严格≥ s²,否则期望重试次数爆炸,无法保证常数时间构造】
内存布局与查询逻辑实现
主表T为长度m的指针数组,T[j]为空指针表示Sⱼ为空,为单元素时直接存数据,为多元素时指向一个大小为mⱼ的二级表Tⱼ。
查询键k时,先计算j = h₁(k),若T[j]是单值则直接比对返回;若T[j]是指针,则计算i = h₂ⱼ(k),访问Tⱼ[i]并比对——两次散列+一次比对即完成,无循环、无回溯。
插入操作不可行,此结构仅支持静态构建后只读查询;删除需重建整个结构。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











