哈希存储:字符串存储、数字存储

本文介绍了哈希存储方法,包括字符串存储和数字存储。在字符串存储中,利用map和进制转换来实现,对于数字存储,直接定址法被提及。文章详细阐述了散列函数如直接定址、线性探查和平方探查解决冲突的方法,并给出了具体的应用实例。

1 方法概括

(1)字符串存储

  • map<int, string> 和 map<string int>
  • 进制转换 + 直接定址法

(2)数字存储

  • int arr[N] (直接定址法、除留余数法(有冲突))

2 理论

2.1 散列函数

  1. 直接定址
    恒等变换:H[key] = key(常用
    线性变换:H[key] = a*key + b

  2. 除留余数
    H[key] = key % mod(常用)(H的表长 TSize>=mod:mod=TSize=素数

  3. 平方取中

2.2 解决冲突

  1. 线性探查
    若对于key, H[key]已被占用
    则:一直 (H[key] +1)%SIZE(H[key]++,循环表长),直到找到空位

  2. 平方探查
    若对于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,循环表长),直到找到空位

  3. 链地址 / 拉链
    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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值