散列表-hash
散列表的直观感受就是用一个有几个分格的书架摆放一堆各种各样的书。
我们试图把同一类书放到一起,
又试图把他们成尽可能多的类,以方便我们能完全按照格子的分类检索。
对于使用不同分类方法生成的各个分类的集合而言,
分类方法即是散列函数,由散列函数给出某个对象<数字字符等>在这个集合中所属的类。
这个时候就可以说散列表这个概念了,散列表就是上面那个集合。
哈哈哈这种说法也太次奥了。
设计散列函数
h(key)= code
-
直接定址
由关键词的某个线性函数获得地址 -
除留余数法
一堆数字 34 456 7 78 231 456 75 423 21 44
看起来没有什么联系,是否就要用上几百个位置按他们的值的顺序
放置呢?
如果让他们对11取余,则是完全能把他们分成有限的几组的 -
数字分析法
身份证号码,不同的位上的数字组合代表着不同的意义,根据这些意义我们就能把一些数字分类 -
折叠法
分割关键字后叠加
如同123456
分割成12
34
56
加起来:12+34+56 = 102
就生成了123456对应的分类码 -
平法取中法
和前者都是使取定的位更为多变
<受到更多位上数字的影响-降低冲突概率>
简单实现
-
联系实际,牛津词典就是妙绝的散列表
至少我们使用词典时不会有“遍历词典”的奇怪想法
我们会根据某个单词的拼写顺序检索字典中对应的部分
这样,即使考虑到不是一下就能翻到我们想要的那一页,我们查词典时翻动的次数在很大程度也取决于单词的长度,而和词典中单词的总量无关。
仿照字典的思路,我们可以完成一个简单的名字表
把所有人的名字散列成26类,相同类的人名放到一起。
typedef struct hashNode{
public:
hashNode* _front,*_behind;//节点串接
string name;
}*hashTable;
1、取名字的首拼,取整形对26取余(众所周知,英文字母只有26个)。
2、获得的整数对26取余,获得分类。
3、相同分类的人名组成一个链表。
int hashFunc(string name)
{
return ((int)name[0])%26;
}
当然,这并不让人满意,毕竟相较于可能的人名数量,26这个分类数还是太小,那么我们可以对人名的第二个字母做同样的操作,把第一次的分类再分成26组,以此类推,直到你满意为止。
void addName(hashNode ht[],string& name)
{
int Loc = hashFunc(name);
hashTable htxd;
hashTable htx = &ht[Loc];
if(htx->name.empty()){
htx->name = name;cout<<"here0,fill the name you gave at "<<Loc<<endl;
}else{
while(htx->_behind != NULL){
htx = htx->_behind;
}
htxd = new hashNode;///malloc和含有string成员的结构冲突<并没有调用string的 cstr初始化string>
htx->_behind = htxd;
htx = htx->_behind;
if(htx!=NULL)
htx->name = name;
}
}