开放定址法(开地址法)、 链地址法(拉链法)、 再哈希法(双哈希函数法)、 建立一个公共溢出区,而最常用的就是开发定址法和链地址法。
1、开放定址法
如果两个数据元素的哈希值相同,则在哈希表中为后插入的数据元素另外选择一个表项。当程序查找哈希表时,如果没有在第一个对应的哈希表项中找到符合查找要求的数据元素,程序就会继续往后查找,直到找到一个符合查找要求的数据元素,或者遇到一个空的表项。线性探测带来的最大问题就是冲突的堆积,你把别人预定的坑占了,别人也就要像你一样去找坑。改进的办法有二次方探测法和随机数探测法。开放地址法包括线性探测、二次探测以及双重散列等方法。
设计思路:有冲突时就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总能找到,并将数据元素存入。
含义:一旦冲突,就找附近(下一个)空地址存入。
具体实现:
1) 线性探测法
Hi=(Hash(key)+di) mod m ( 1≤i < m ) 其中: Hash(key)为哈希函数 m为哈希表长度 di 为增量序列 1,2,…m-1,且di=i
例:
关键码集为 {47,7,29,11,16,92,22,8,3},
设:哈希表表长为m=11; 哈希函数为Hash(key)=key mod 11; 拟用线性探测法处理冲突。建哈希表如下:
解释:
① 47、7(以及11、16、92)均是由哈希函数得到的没有冲突的哈希地址;
② Hash(29)=7,哈希地址有冲突,需寻找下一个空的哈希地址:由H1=(Hash(29)+1) mod 11=8,哈希地址8为空,因此将29存入。
③ 另外,22、8、3同样在哈希地址上有冲突,也是由H1找到空的哈希地址的。其中3 还连续移动了两次(二次聚集)
int FindHash(SeqList* pL, KeyType K) { int c=0; int p=Hash(K); /*求得哈希地址*/ while(pL->data[p].key!=NULL_KEY && K!=pL->data[p].key && ++c<MAXNUM) p=Hash(K+c); if(K==pL->data[p].key) { printf("\n成功找到 %d", K); return p; /*查找成功,p返回待查数据元素下标*/ } else if(pL->data[p].key==NULL_KEY) { printf("\n无法找到 %d , 在位置 %d 插入。", K,p); pL->data[p].key = K; pL->n++; return p; } else { printf("\n无法找到 %d , 表已满。", K); return -1; } }