一.整数的散列
把输入的数作为数组下标来对这个数的性质进行统计;
示例1:
#include<cstdio>
const int maxn = 100010 ;
bool hashTable[maxn] = {false} ;
int main() {
int n , m , x ;
scanf("%d%d",&n,&m) ;
for(int i = 0 ; i < n ; i ++) {
scanf("%d",&x) ;
hashTable[x] = true ;
}
for(int i = 0 ; i < m ; i ++) {
scanf("%d",&x) ;
if(hashTable[x] == true) printf("YES\n") ;
else printf("NO\n") ;
}
return 0 ;
}
二.其他元素的散列
将元素通过 散列函数H 转换成整数,使该整数尽量唯一代表此元素;
1.散列函数:
1).直接定址法:H(i)=i 或 H(i)=k* i+b;
2).除留余数法:H(i)=i%mod;
2.冲突解决:
1).线性探查法:检查下一个位置是否被占,若超过表长则回到表的首位继续检查,此做法导致扎堆;
2).平方探查法:按以下顺序:H(i)+1* 1、H(i)-1* 1、H(i)+2* 2、H(i)-2* 2;
3).链地址法:造一条单链表;
三.字符串的散列
示例1:S由大写字母构成
e.g.字符串BCD等于26进制下的234,将(234)转换为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 ;
}
示例2:S由大小写字母构成
int hashFunc(char S[] , int len) {
int id = 0 ;
for(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 ;
}
示例3:S末尾是确定个数的数字
int hashFunc(char S[] , int len) {
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 ;
}
四.题目
1.PAT A1084
思路:
枚举查此键是否损坏,利用hashTable记录是否已经输出过;
注意:
1).bool hashTable[128] = {false} ;
2).循环里的 i、j 的值只在此循环内有效,需要在 for 外定义才能在全局有效,并且不能两次用 int;
代码:
#include<cstdio>
#include<cstring>
int main() {
bool hashTable[128] = {false} ;
char str1[100] , str2[100] ;
scanf("%s",str1) ;
scanf("%s",str2) ;
int len1 = strlen(str1) ;
int len2 = strlen(str2) ;
for(int i = 0 ; i < len1 ; i ++) {
char c1 , c2 ;
int j ;
for(j = 0 ; j < len2 ; j ++) {
c1 = str1[i] ;
c2 = str2[j] ;
if(c1 >= 'a' && c1 <= 'z') c1 -= 32 ;
if(c2 >= 'a' && c2 <= 'z') c2 -= 32 ;
if(c1 == c2) break ;
}
if(j == len2 && hashTable[c1] == false) {
printf("%c",c1) ;
hashTable[c1] = true ;
}
}
return 0 ;
}
2.PAT B1033
思路:
hashTable保存损坏的键(小写),枚举输入的字符串;
注意:
bool hashTable[256] = {true} ;
错误,什么都不输出;
bool hashTable[256] ; memset(hashTable , true , sizeof(hashTable)) ;
正确;
因为第一种赋值方法只能用于初值为0(false)的情况;若为其他值,则只给数组第一个 hashTable[0] 赋值
代码:
#include<cstdio>
#include<cstring>
using namespace std ;
const int maxn = 100000 + 10 ;
int main() {
bool hashTable[256] ;
memset(hashTable , true , sizeof(hashTable)) ;
char str1[maxn] , str2[maxn] ;
scanf("%s",str1) ;
scanf("%s",str2) ;
int len1 = strlen(str1) ;
int len2 = strlen(str2) ;
for(int i = 0 ; i < len1 ; i ++) {
if(str1[i] >= 'A' && str1[i] <= 'Z') str1[i] += 32 ;
hashTable[str1[i]] = false ;
}
for(int i = 0 ; i < len2 ; i ++) {
if(str2[i] >= 'A' && str2[i] <= 'Z') {
int c2 = str2[i] + 32 ;
if(hashTable[c2] == true && hashTable['+'] == true) printf("%c",str2[i]) ;
}
else if(hashTable[str2[i]] == true) printf("%c",str2[i]) ;
}
printf("\n") ;
return 0 ;
}
3.PAT B1039
思路:
1).怎么计算缺少的珠子:hashTable --,若 <0 则缺少的珠子数 miss 加 1,最后通过判断 miss 的正负确定是 Yes 或 No;
2).算多出的珠子时,直接将两串长度相减;
注意:
最后输出时不是YES NO,是Yes No;(我是白痴?多看看其他博客,也有人犯和我一样的错误);
代码:
#include<cstdio>
#include<cstring>
using namespace std ;
const int maxn = 1010 ;
int main() {
char str1[maxn] , str2[maxn] ;
int hashTable[128] = {0} ;
scanf("%s",str1) ;
scanf("%s",str2) ;
int len1 = strlen(str1) ;
int len2 = strlen(str2) ;
for(int i = 0 ; i < len1 ; i ++) {
hashTable[str1[i]] ++ ;
}
int miss = 0 ;
for(int i = 0 ; i < len2 ; i ++) {
hashTable[str2[i]] -- ;
if(hashTable[str2[i]] < 0) miss ++ ;
}
if(miss == 0) printf("Yes %d\n",len1 - len2) ;
else printf("No %d\n",miss) ;
return 0 ;
}