算法笔记之第四章 散列

散列定义与整数散列

给出N个数,问另外M个数是否在N个数中出现过?若用遍历的方法则时间复杂度太大( O ( N M ) O(NM) )不妨用空间换时间,设立一个bool型数组hashTable[10010],hashTable[x]==true表示某整数x在N个数中出现过,这样一开始读入N时就能进行处理,时间复杂度 O ( N + M ) O(N+M)

#include<cstdio>
const int maxn = 100010;
int hashTable[maxn] = {0};
int main() {
    int n, m, x;
    scanf("%d%d", &n, &m);
    for(int i = 0;i < n; i ++) {
    scanf("%d", &x);
    hashTable[x] = true; //数字x出现过
}
for(int i = 0;i < m; i++) {
    scanf("%d", &x);
    if(hashTable[x] == true){
        printf("YES\n");
    } else {
        printf("NO\n");
    }
}
return 0;
}

如果要求x出现的次数

#include<cstdio>
const int maxn = 100010;
int hashTable[maxn] = {0};
int main() {
    int n, m, x;
    scanf("%d%d", &n, &m);
    for(int i = 0;i < n; i ++) {
    scanf("%d", &x);
    hashTable[x]++;
}
for(int i = 0; i < m; i++) {
    scanf("%d", &x);
    printf("%d\n", hashTable[x]);
    }
    return 0;
}

特点:直接把输入的数作为数组的下标

散列:通过函数把“元素”转化为整数,使得整数可以唯一地代表这个“元素”(比如把x变成数组下标)

除留余数法: H ( k e y ) = k e y % m o d H(key)=key\%mod ,表长TSize必须不小于mod。下文取TSize是一个素数,mod取与TSize相等。

解决两个key的H(key)值相同(即冲突)的办法:
(1)线性探查法:检查下一个位置(H(key)+1)是否被占,不断往下推
(2)平方探查法:检查下列位置 H ( k e y ) + i 2 H(key)+i^2 i i 为正整数
(3)链地址法(拉链法):将所有H(key)相同的key连接成一条单链表(见7.3节)

字符串hash初步

字符串hash是指将一个字符串S映射为一个整数使之唯一表出S。

例:假设字符串均由大写字母A-Z构成,A-Z对应0-25,再将二十六进制转换为十进制

int hashFunc(char S[], int len) { //hash函数将字符串S转换为整数
    int id = 0;
    for(int i = 0; i < len; i++) {
        id = id * 26+ (S[i] - 'A'); //将二十六进制转换为十进制
        }
        return id;
    }

如果出现小写字母,把a-z作为26-51,变为五十二进制转换为十进制的问题,做法也是相同的

int hashFunc(char S[], int len) { //hash函数,将字符串S转换为整数
    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;

如果出现了数字
(1)可以增大进制到62
(2)直接把数字拼上去,比如

int hashFunc(char S[], int len) { //hash函数,将字符串S转换为整数
    int id = 0;
    for(int i = 0; i < len - 1; i++) {
        id = id * 26 + (S[i] - 'A');
    }
    id = id * 10 + (S[len - 1] - '0');
    return id; 

总结进制转换 id=id乘原进制位数+(S代表的长度-原进制首位字符)

问题:给出N个字符串(恰好由三位大写字母组成),再给出M个查询字符,求每个查询字符在N个字符串中出现的次数

#include<cstdio>
const int maxn = 100;
char S[maxn] [5], temp[5];
int hashTable[26 * 26 * 26 +10];
int hashFunc(char S[], int len) { //hash函数,将字符串S转换为整数
    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++) {
        scanf("%s", S[i]);
        int id = hashFunc(S[i], 3); //将字符串S[i]转换为整数
        hashTable[id]++; //该字符串的出现次数加1
    }
    for(int i = 0; i < m; i++) {
        scanf("%s", temp);
        int id = hashFunc(temp, 3); //将字符串temp转换为整数
        printf("%d\n", hashTable[id]); //输出该字符串的出现次数

猜你喜欢

转载自blog.csdn.net/weixin_44770248/article/details/89677670
今日推荐