一、基本概念
1.散列表,也叫哈希表:存放关键码散列地址的数组;
2.散列地址冲突:将不同的关键码映射到同一个散列地址上;
(一般关键码集合比散列地址集合打得多)
3.散列函数选取原则:计算简单&分布均匀
二、散列函数构造方法
1.直接定址法:
一一映射,要求散列地址空间的大小与关键吗集合的大小相同。
2.数字分析法:
取关键字中的若干位或其组合作哈希地址。
3.平方取中法:
取关键字平方后中间几位作哈希地址。
4.折叠法:
部分数字的叠加方法有:移位法和分界法。
5.随机数法:
取关键字的随机函数值作为散列地址。
6.除留余数法:
散列函数为:hash(key) = key%p p<=m (m为散列表中允许的地址数)。
根据经验,取一个小于等于m的置数p,得到的散列函数较好。
若p<m,存在几个散列地址在一开始不可能用散列函数计算出来,只可能在处理溢出是用到这些地址。
7.乘余取整法:
散列函数为: hash(key)= [n*(A*key%1)] (用[]表示下取整,0<A<1, n为常数)
三、常见字符串哈希函数
常见的8个字符串哈希函数有:
SDBMHash, RSHash, JSHash, PJWHash, ELFHash, BKDRHash, DJBHash, APHash.
SDBMHash, RSHash, JSHash, PJWHash, ELFHash, BKDRHash, DJBHash, APHash.
这些都是计算机科学家研究出来的,计算出来的哈希地址分布均匀,冲突较少。
使用时需注意:返回值要%地址总数,才会映射到哈希表的地址范围内。
下面的程序用来测试产生冲突的情况:
#include
#define BUCKETS 101
unsigned int SDBMHash(char *str){
unsigned int hash =0;
while (*str)
hash =(*str++)+(hash<<6)+(hash<<16)-hash;
return (hash & 0x7fffffff)%BUCKETS;
}
int main(){
char *keywords[]={
"auto","break","case","char","const","continue","default","do",
"double","else","enum","extern","float","for","goto","if",
"int","long","register","return","short","signed","sizeof","static",
"struct","switch","typedef","union","unsigned","void","volatile","while"
};
int count[BUCKETS]={0};
int number=sizeof(keywords) /sizeof(keywords[0]);
int i;
for (i=0;i
运行结果: 结果显示的依次为——关键字、散列地址和该地址的映射次数
![]()
说明:
1.一维数组初始化时,若为全部赋值,则剩下的被初始化为0;
2.字符串数组可以定义为 char *a[]
字符串用指针标志,eg: char *a[5]={"red","yellow","blue","white","black"};
向散列函数传递的实参为char *,即keywords[i].
另外,sizeof(char *) =4.
3.printf:
格式替代符 %s:字符串
%-10s 格式为左对齐且宽度为10的字符串代替(-表示左对齐,不使用则是右对齐)