您的位置:首页 > 其它

算法初步——散列

2018-01-09 11:32 148 查看

散列的定义与整数散列

  • 题目要求:M个预查询的数中每个数在N个数中出现的次数 思路:设定一个int型数组 hashTable[10010] ,然后在输入 N 个数时进行预处理,即当输入的数为 x 时 ,就令 hashTable[x]++,时间复杂度为 O(N+M)
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    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) {    // 输出 M 个数中每个数在 N 个数中出现的次数
    scanf("%d", x);
    printf("%d\n", hashTable[x]);
    }
    
    return 0;
    }
  • 但是这个策略暂时还有一个问题——如果输入可能是10^9大小的整数,或者甚至是一个字符串,就不能将它们直接作为数组下标了,这时候可以使用散列,散列即 ” 将元素通过一个函数转换为整数,使得该整数可以尽量唯一的代表这个元素 “ ,常用的散列函数有 直接定址法、平方取中法、除留余数法等。
  • 除留余数法,H(key) = key % mod
  • 解决冲突的方法:线性探测法、平方探测法、链地址法
  •  

    字符串hash初步

    • 先假设字符串均由大写字母 A~Z 构成 不妨把 A~Z 视为 0~25 ,这样就把26个大写字母对应到二十六进制中
    • 接着按照将二十六进制转换为十进制的思路,便可实现将字符串映射为整数的需求
      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 视为 0~25 ,而把 a~z 视为 26~51 
    • 就变成了五十二进制转换为十进制的问题
      int hashFunc1(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;
      } 
  • 而如果出现了数字,一般有两种处理方法:
      按照小写字母的处理方法,增大进制数至62
    1. 如果保证在字符串的末尾是确定个数的数字,那么就可以把前面的英文字母的部分按上面的思路转换成整数,再将末尾的数字直接拼接上去。例如对由三个字符加一位数字组成的字符串 ”BCD4“ 来说,就可以先将前面的 ”BCD“ 转换为整数 731 ,然后直接拼接上末位4变为7314即可
      int hashFunc2(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;
      }
  • 以一个问题结尾:给出 N 个字符串(由恰好三位大写字母组成),再给出 M 个查询字符串,问每个查询字符串在N个字符串中出现的次数
      思路:将字符串转换为整数,然后利用上面的整数散列解决该问题
      #include <cstdio>
      #include <string>
      #include <algorithm>
      #include <cmath>
      using namespace std;
      
      const  int maxn = 100;
      char S[maxn][5], temp[5];
      int hashTable[26*26*26 + 10] = {0};
      
      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) {
      scanf("%s", S[i]);
      int id = hashFunc(S[i], 3);        // 将字符串转换为整数
      hashTable[id]++;                // 该字符串出现次数+1
      }
      for(int i=0; i<m; ++i) {
      scanf("%s", temp);
      int id = hashFunc(temp, 3);        // 将字符串 temp 转换为整数
      printf("%d\n", hashTable[id]);    // 输出该字符串出现次数
      }
      
      return 0;
      }

       

     

  • 内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: