散列的定义与整数散列
散列的定义
——将元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素
在这个过程中,这个转换函数称为散列函数H,原始元素记为key,那么转换后的整数就是H(key)
常用散列函数
对于key是整数的情况,常用的方法有直接定址法,平方取中法和除留余数法,其使用如下:
- 直接定址法
1.H(key) = key //恒等变换
2.H(key) = a * key + b; //线性变换
- 平方取中法(待补充)
- 除留余数法
H(key) = key % mod;
关于除留余数法
通过除留余数法的散列函数,我们可以将很大的数转换为不超过mod的整数,这样在key很大时H(key)也可以作为可行的数组下标(表长TSize要不小于mod,不然会越界)
当mod时一个素数时,H(key)能够尽可能的覆盖[0,mod)范围内的每一个数
冲突的解决:
- 线性探查法
- 平方探查法
- 链地址法
通常可以使用标准模板库中的map来直接使用hash的功能
字符串hash初步
基本思路:将字符串通过进制转换的方式转换为整数
- 若仅包含大写字母,则考虑从26进制转换为10进制
int hashFunc(char S[],int len) { //hash函数,将字符串扎转换为整数
int id = 0;
for (int i = 0; i < len; i++) {
id = id * 26 + (S[i] - 'A');
}
return id;
}
- 若包含大写字母和小写字母,考虑由52进制转换10进制
int hashFunc(char S[],int len) { //hash函数,将字符串扎转换为整数
int id = 0;
for (int i = 0; i < len; i++) {
if (S[i] >= 'A' && S[i] <= 'Z') {
id = id * 52 + (S[i] - 'A');
}
else if (S[i] >= 'a' && S[i] <= 'z') {
id = id * 52 + (S[i] = 'a') + 26;
}
}
return id;
}
- 若除字母外还包括数字考虑①按照小写字母的处理方法增大进制数至62;②若保证在字符串末尾是确定位数的数字,则可以前面的字符照例转换,后面的数字之后拼接上去
例题
题目描述
给出N个恰好由3位大写字母组成的字符串,再给出m个查询字符串,问每个查询字符串在n个字符串中出现的次数
解决方案
#include<cstdio>
const int maxn = 100;
char S[maxn][5], temp[5];//定义二维数组S存储N个字符串,一维数组temp存储欲查询字符串
int hashTable[26*26*26 + 10];//存放散列函数转换的整数结果,以对应字符串
int HashFunc(char S[], int len)//将字符串转换为整数
{
int id = 0;
for (int i = 0; i < len; i++)
{
id = id * 26 + (S[i] - 'A');
}
return id;
}
int main()
{
//声明要输入的字符串的个数
int n, m;
scanf("%d%d",&n, &m);
for (int i = 0; i < n; i++)//输入n个字符串并存放到二维数组 S中 ,并将其对应的整数作为下标,找到hashTable对应位置加一
{
scanf("%s",&S[i]);
int id = HashFunc(S[i], 3);
hashTable[id]++;
}
for (int i = 0; i < m; i++)//输入m个查询字符串,并找到hashTable中对应整数坐标内记录的字符串出现次数
{
scanf("%s",&temp);
int id = HashFunc(temp,3);
printf("%d",hashTable[id]);
}
return 0;
}