哈希表
哈希表可以通过关键字直接找到数据的存储位置,其查找效率也相对较高。
哈希表的构造
例如,这里有一个电话簿(查找表),电话簿中有 4 个人的联系方式:
张三 13912345678
李四 15823457890
王五 13409872338
赵六 13805834722
假如想查找李四的电话号码,对于一般的查找方式最先想到的是从头遍历,一一比较。而如果将电话簿构建成一张哈希表,可以直接通过名字“李四”直接找到电话号码在表中的位置。
在构建哈希表时,最重要的是哈希函数的设计。例如设计电话簿案例中的哈希函数为:每个名字的姓的首字母的 ASCII 值即为对应的电话号码的存储位置。这时会发现,张三和赵六两个关键字的姓的首字母都是 Z ,最终求出的电话号码的存储位置相同,这种现象称为冲突。在设计哈希函数时,要尽量地避免冲突现象的发生。 对于哈希表而言,冲突只能尽可能地少,无法完全避免。
哈希函数的构造
常用的哈希函数构造方法有六种: 直接定址法、数字分析法、平方取中法、折叠法、除留余数法和随机法
除留余数法(这里只介绍一种方法,其余的方法想了解的伙伴可自行谷歌百度)
若已知整个哈希表的最大长度m,可以取一个不大于m的数p,然后对该关键字key做取余运算。如: key = key % p
处理冲突的方法
对于哈希表的建立,需要采取合适的哈希函数,但是对于无法避免的冲突,需要采取适当的措施去处理。
常用的处理冲突的方法有几种:: 开放定址法、再哈希法、链地址法、建立一个公共溢出区
开放地址法
开放地址法也有三种方法,这里介绍第一种:线性探测法(在线性探测法中,当遇到冲突时,从发生冲突位置起,每次 +1,向右探测)
例如,在长度为 11 的哈希表中已填写好 17、60 和 29 这 3 个数据(如,其中采用的哈希函数为:key=key%11,现有第4个数据38,当通过哈希函数求得的哈希地址为 5,与 60 冲突,于是使用线性探测法 key=(++key)%m;
代码实现
#include <stdio.h>
#include <stdlib.h>
#define HASHSIZE 7 //定义散列表长为数组的长度
#define NULLKEY -1
typedef struct{
int *elem;//数据元素存储地址,动态分配数组
int count; //当前数据元素个数
}HashTable;
初始化哈希表
void Init(HashTable *hashTable){
int i;
hashTable->elem= (int *)malloc(HASHSIZE*sizeof(int));
hashTable->count=HASHSIZE;
for (i=0;i<HASHSIZE;i++){
hashTable->elem[i]=NULLKEY;
}
}
哈希函数(除留余数法)
int Hash(int data){
return data%HASHSIZE;
}
插入函数
void Insert(HashTable *hashTable,int data){
int hashAddress=Hash(data); //求哈希地址
//发生冲突
while(hashTable->elem[hashAddress]!=NULLKEY){
//利用开放定址法解决冲突
hashAddress=(++hashAddress)%HASHSIZE;
}
hashTable->elem[hashAddress]=data;
}
哈希表的查找算法
int Search(HashTable *hashTable,int data){
int hashAddress=Hash(data); //求哈希地址
while(hashTable->elem[hashAddress]!=data){//发生冲突
//利用开放定址法解决冲突
hashAddress=(++hashAddress)%HASHSIZE;
//如果查找到的地址中数据为NULL,或者经过一圈的遍历回到原位置,则查找失败
if (hashTable->elem[hashAddress]==NULLKEY||hashAddress==Hash(data)){
return -1;
}
}
return hashAddress;
}
主函数
int main(){
int i,result;
HashTable hashTable;
int arr[HASHSIZE]={13,29,27,28,26,30,38};
//初始化哈希表
Init(&hashTable); //引用
//利用插入函数构造哈希表
for (i=0;i<HASHSIZE;i++){
Insert(&hashTable,arr[i]);
}
//调用查找算法
result= Search(&hashTable,29);//引用
if (result == -1) {
printf("查找失败");
} else {
printf("29在哈希表中的位置是:%d",result+1);
}
return 0;
}
运行结果
29在哈希表中的位置是:2