字符串算法————hash哈希链表

虽然已经有映射函数map,而且其适用范围还更广,但在字符串上还是哈希更好理解~~(哈希在密码学上很重要,抱有某种目的同学们注意危险言论了)~~
学过高中生物的同学们应该对胞间连丝印象很深,hash和map就是一种信息学胞间连丝,很形象。
hash是一种对应法则,将字符串按照这种法则运算,所得的权值有可能会有重复(下文称为冲突),所以我们运算字符串的权值时会采用其他进制,根据题意需具体分析。FOR INSTANCE,若只会出现小写字母则31进制足以撑场,但如果是大小写字母都有,那就要用131进制比较合适了。
模板如下:

const int base=131;
inline int hash(string c){
	int len=c.size();
	int ret=0;
	for(int i=0;i<=len-1;i++){
	 	ret*=base,ret+=c[i]-'A';
	}
	return ret;
}

这里的base就是进制了,具体情况具体分析。

好了,那我们如何储存字符串信息呢?
这里要用链表了,也就是哈希表。
因为我们计算完哈希值后,要表明这个字符串被加进了字典中,按朴素思想应该直接flag[hash(s)]=1,但这样数组flag会开的很大,根本存不下,所以我们对哈希值采用取模(模数不要太大,我比较喜欢19997),优先选择质数~~,比如19260817这时有同学就要疑惑了,这不明显会出问题吗? 比如1%19997=1,19998%19997==1,不就会冲突了吗?

嘿嘿,这时链表就有用了。
我们开一个结构体,储存两个信息:val和nt;
nt很明显是存下一个节点的,而val则用来储存字符串的原hash值
当我们算出hash(s)==v时,设t=v%mod,就在t的后面拉一条链,串起来。

代码:

struct node{
	int nt,val;
}e[200018];
inline void update(string s){
	int x=hash(s);
	cnt++;
	e[cnt].nt=head[x%mod];
	e[cnt].val=x;
	head[x%mod]=cnt;
}

当我们查找字典中是否存在字符串s时,先计算出其哈希值x,如果存在,那么它一定会被保存在x%mod后面,我们只需在x%mod后面的那条链里扫一遍,查看是否有一个点权值为x就OK了。
代码:

inline int ask(string ch){
	int flag=0;
	int x=hash(ch);
	for(int i=head[x%mod];i;i=e[i].nt){
		if(e[i].val==x){
			flag=1;
		}
	}
	return flag;
}

}
ps:head[k]数组存的是k号拉链后面的第一个点在e数组中的编号(但实际上这个点是最后一个插入此链的)

你可能感兴趣的:(字符串算法)