散列表是一种搜索算法,它可以跟据各个元素的值来确定存储位置,然后将位置保管在散列表中,从而实现数据的高速搜索。器中散列表是一种数据结构,能对包含关键字的数据集合高效的执行插入,搜索,删除操作。
散列表由容纳m个元素的数组T,以及跟据关键字决定数组下标的函数共同组成,也就是说,我们要将数据的关键字输入该函数,由该函数决定数据在数组中的位置。
h(k)称为散列函数,该函数的返回值成为散列值,散列函数求出的值范围为0至m-1之间(m为数组T的长度)。为了满足这一条件,函数内使用取余运算,保证输出值为0至m-1之间的整数。
h(k)=kmodm
就是这么一种散列函数,会产生不同key对应同一散列值的情况,即出现“冲突”。
开放寻址法是解决这类问题的常用手段
在双散列结构中一旦出现冲突,程序会调用第二个散列函数来求散列值
H(k)=h(k,i)=(h1(k)+i*h2(k))modm
散列函数h(k,i)拥有关键字k和整数i两个参数,这里的i是发生冲突后计算下一个散列值的次数。也就是说,只要散列函数H(K)起了冲突,就会依次调用h(k,0),h(k,1),h(k,2)....,直到不发生冲突为止,然后返回这个h(k,i)的值作为散列值。
要注意的是,因为下标每次移动h(k)个位置,所以必须保证T的长度m与h2(k)互质,否则会出现无法生成下标的情况,这种时候,我们可以特意让m为质数,然后取一个小于m的值作为h2(k),从而避免上述情况发生。
int h1(int key) { return key%m; } int h2(int key) { return 1+(key%(m-1)); } int h(int key,int i) { return (h1(key)+i*h2(key))%m; } int insert(int key) { int i=0; while(true){ j=h(key,i); if(t[j]==NIL){//来判断当前位置是否为空 t[j]=key; return j; }else{ i=i+1; } } } int search(int key) { i=0; while(true){ j=h(key,i); if(t[j]==key){ return j; }else if(t[i]==NIL||i>=m){ return NIL; }else{ i=i+1; } } }
散列表用途不同会用到各种算法(比如加密技术),有时候还会用到启发式搜索。
例题:AOJ ALDS1_4C:Dictionary
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int m=1046527; const int NIL=-1; const int l=14; typedef long long LL; char H[m][l]; int getchar(char ch) { if(ch=='A'){ return 1; }else if(ch=='C'){ return 2; }else if(ch=='G'){ return 3; }else if(ch=='T'){ return 4; }else{ return 0; } } LL getkey(char str[]) { LL sum=0,p=1; int len=strlen(str); for(int i=0;i<len;i++){ sum+=p*(getchar(str[i])); p*=5; } return sum; } int h1(int key) { return key%m; } int h2(int key) { return 1+(key%(m-1)); } int find(char str[]) { LL key; key=getkey(str); for(int i=0;;i++){ int h=(h1(key)+i*h2(key))%m; if(strcmp(H[h],str)==0){ return 1; }else if(strlen(H[h])==0){ return 0; } } return 0; } int insert(char str[]) { LL key; key=getkey(str); for(int i=0;;i++){ int h=(h1(key)+i*h2(key))%m; if(strcmp(H[h],str)==0){ return 1; }else if(strlen(H[h])==0){ strcpy(H[h],str); return 0; } } return 0; } int main() { int n; char str[l],com[9]; for(int i=0;i<m;i++){ H[i][0]=0; } scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%s %s",com,str); if(com[0]=='i'){ insert(str); }else{ if(find(str)){ printf("yes\n"); }else{ printf("no\n"); } } } return 0; } /* 6 insert AAA insert AAC find AAA find CCC insert CCC find CCC */