散列表(一)基础
很久以前就接触过hash,可是当时链表都没有写过,毕竟在竞赛中用得太少了。近段时间做了不少网络流的题目,都是数组模拟的链表存储图的,再回过头看hash,就很好理解了。
hash的资料到处都有,就不再废话了。处理冲突一般有两种:分离链接法和开放定址法。就是挂链表和抢别人的位置嘛。至于什么平方取中啊,再散列啊,虽然有所了解,但还是继续纸上谈兵吧。实际应用的话熟练掌握几个hash函数的方法并能熟练运用就行了。
相关资料有:
最常用的就是把一个字符串函数hash然后挂链表了,附POJ2503程序:
const maxsize=99997; var s,enword,foreign:string; en,str:array[0..maxsize*10] of string; head:array[0..maxsize] of longint; next:array[0..maxsize*10] of longint; size:longint; space:longint; function hash(var s:string):longint; const seed=31; var i:longint; begin hash:=0; for i:=1 to length(s) do hash:=(hash*seed+ord(s[i])) and $FFFFFF; exit(hash mod maxsize); end; procedure insert(var enword,foreign:string); var hashval:longint; begin inc(size); str[size]:=foreign; en[size]:=enword; hashval:=hash(foreign); next[size]:=head[hashval]; head[hashval]:=size; end; function find(var s:string):string; var i:longint; begin i:=head[hash(s)]; while i<>0 do begin if str[i]=s then exit(en[i]); i:=next[i]; end; exit('eh'); end; begin readln(s); while s<>'' do begin space:=pos(' ',s); enword:=copy(s,1,space-1); foreign:=copy(s,space+1,length(s)-space); insert(enword,foreign); readln(s); end; while not eof do begin readln(s); writeln(find(s)); end; end.
有时候用tire也不错,附单词查找树的代码,虽然与hash无直接关系。
var tree:array[0..500000,'A'..'Z']of longint; tot,i,j,k:longint; s:ansistring; procedure insert(s:ansistring); var i,j,k,x:longint; begin x:=1; for i:=1 to length(s) do begin if tree[x,s[i]]=0 then begin inc(tot); tree[x,s[i]]:=tot; x:=tot; end else x:=tree[x,s[i]]; end; end; begin assign(input,'tree.in'); reset(input); assign(output,'tree.out'); rewrite(output); fillchar(tree,sizeof(tree),0); tot:=0; while not eof do begin readln(s); insert(s); end; writeln(tot+1); close(output); close(input); end.
有时候可以根据数据的特殊性质来给出更有针对性的hash方法,比如hash一个排列,最好用康托展开了
如果是不怎么长的固定的字符组成的字符串,则可以映射为一个数字,如POJ1200,附代码
{ 一个字符串由 NC 种不同的字符构成,问其中字串长度为 N 的不同字串有多少个。 当然可以直接枚举,但题目中谈到了 NC,可将 NC 种不同的字符转化为 NC 进制数,然后将字串转化为整数来判断。 或者将它们转化为 hash 来判断。 http://www.chenyajun.com/2010/04/04/4774 http://www.cublog.cn/u3/102624/showart_2042806.html 练习hash的入门题,不过这题能充分利用条件产生nc进制的数来构造没有冲突hash函数 开始时把j打成i了…… 2011年6月21日23:01:48 } var s:ansistring; i,j,k,ans,n,m:longint; f:array['!'..'~'] of longint; sum:longint; flag:array[0..16000000] of boolean; begin readln(n,m); readln(s); for i:=1 to length(s) do begin if f[s[i]]=0 then begin f[s[i]]:=k; inc(k); end; if k>m then break; end; ans:=length(s)-n+1; for i:=1 to length(s)-n+1 do begin sum:=0; for j:=i to i+n-1 do sum:=sum*m+f[s[j]]; if not flag[sum] then flag[sum]:=true else dec(ans); end; writeln(ans); end.