文章目录
1 方法概括
(1)字符串存储
- map<int, string> 和 map<string int>
- 进制转换 + 直接定址法
(2)数字存储
- int arr[N] (直接定址法、除留余数法(有冲突))
2 理论
2.1 散列函数
-
直接定址
恒等变换:H[key] = key(常用)
线性变换:H[key] = a*key + b -
除留余数
H[key] = key % mod(常用)(H的表长 TSize>=mod:mod=TSize=素数) -
平方取中
2.2 解决冲突
-
线性探查
若对于key, H[key]已被占用
则:一直 (H[key] +1)%SIZE(H[key]++,循环表长),直到找到空位 -
平方探查
若对于key, H[key]已被占用
则:k=1,2,…, 一直 ((H[key] ± k 2 k^2 k2)%SIZE+SIZE)%SIZE(H[key]± k 2 k^2 k2,循环表长,防止H[key]- k 2 k^2 k2<0》),直到找到空位
或只正向平方探查:k=1,2,…, 一直 (H[key] + k 2 k^2 k2)%SIZE(H[key]+ k 2 k^2 k2,循环表长),直到找到空位 -
链地址 / 拉链
Link[0]~Link[mod-1],mod可=TSize
Link[i]:存一个单链表,H[key] = i 的所有结点(即有冲突的所有结点)
3 具体方法
3.1 数字存储
3.1.1 直接定址(当N<10^5 , N为非负整数)
例题:
已知N个正整数A[N],M个正整数B[M](N,M<=
1
0
5
10^5
105)
-
问1:将B[M]在A[N]中是否出现
输入:
A{2, 3, 6, 10}
B{0, 3}
输出:
NO
YES -
问2:将B[M]在A[N]中出现的次数
输入:
A{2,3,3,10}
B{0, 3}
输出:
0
2
(1)求是否查找成功,用bool
哈希:
bool hashTable[10000+10]; (默认=false)
遍历B[M]:hashTable[B[i]] = true;
遍历A[N]:if hashTable[A[i]] == true,则:找到,输出YES
O(M+N)
(2)求查中次数,用int
哈希:
int hashTable[10000+10]; (默认=0)
遍历B[M]:hashTable[B[i]] ++;
遍历A[N]:输出 hashTable[A[i]]
3.2 字符串存储
3.2.1 map
3.2.2 进制转换
3.2.2.1 string为大写字母
(1)代码
const int TSize = 26*26*26 + 10;
bool hashTable[TSize];
// 字符串:3个字符(大写字母)
int hashFun(char str[]){
int id=0;
for(int i=0; i<strlen(str); i++){
id = id*26 + (str[i] - 'A');
}
return id;
}
(2)小结
- A~Z:26进制 转为 10进制
id = …+ (str[1]-‘A’)* 2 6 1 26^1 261 + (str[0]-‘A’)* 2 6 0 26^0 260
3.2.2.2 string为字母
(1)代码
const int TSize = 52*52*52 + 10;
bool hashTable[TSize];
// 字符串:3个字符(字母)
int hashFun(char str[]){
int id=0;
for(int i=0; i<strlen(str); i++){
if(str[i]>='A' && str[i]<='Z'){
id = id*52 + (str[i] - 'A');
}else if(str[i]>='a' && str[i]<='z'){
id = id*52 + (str[i] - 'a') + 26;
}
}
return id;
}
(2)小结
- A ~ Z,a ~ z:26+26=52进制 转为 10进制
3.2.2.3 string为字母+数字
(1)代码
const int TSize = 62*62*62 + 10;
bool hashTable[TSize];
// 字符串:3个字符(字母+数字)
int hashFun(char str[]){
int id=0;
for(int i=0; i<strlen(str); i++){
if(str[i]>='0' && str[i]<='9'){
id = id*62 + (str[i] - '0');
}
else if(str[i]>='A' && str[i]<='Z'){
id = id*62 + (str[i] - 'A') + 10;
}else if(str[i]>='a' && str[i]<='z'){
id = id*62 + (str[i] - 'a') + 10 + 26;
}
}
return id;
}
(2)小结
- 0~9,A ~ Z, a ~ z: 10+26+26=62进制 转为 10进制
- -ASCII码:‘0’ < ‘A’ < ‘a’
因此,进制转换只能此顺序
3.2.2.4 string为字母+数字(末尾)
const int TSize = 52*52*52*10 + 10;
bool hashTable[TSize];
// 字符串:4个字符(3个字母+末尾一个数字)
int hashFun(char str[]){
int id=0;
for(int i=0; i<strlen(str)-1; i++){
if(str[i]>='A' && str[i]<='Z'){
id = id*52 + (str[i] - 'A');
}else if(str[i]>='a' && str[i]<='z'){
id = id*52 + (str[i] - 'a') + 26;
}
}
id = id*10 + (str[strlen(str)-1] - '0'); //末尾1个数字
return id;
}
(2)小结:
- A ~ Z,a ~ z:52进制 转为 10进制,再直接 拼接 k个数字
3.2.2.5 扩展(字符串较长)
H[i] = H[i-1]*P+ index(str[i]) (P为进制)
当str都为大写字母 && len较小时
H[i] = H[i-1]*26 + str[i] - ‘A’
当str都为大写字母 && len较大时
const int MOD = 1e9 + 7;
const int P = 1e7+19;
long long H[i] = (H[i-1]*P + str[i] - ‘A’)%MOD
本文介绍了哈希存储方法,包括字符串存储和数字存储。在字符串存储中,利用map和进制转换来实现,对于数字存储,直接定址法被提及。文章详细阐述了散列函数如直接定址、线性探查和平方探查解决冲突的方法,并给出了具体的应用实例。
501

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



