哈希查找算法

3,068 阅读4分钟

哈希表

哈希表可以通过关键字直接找到数据的存储位置,其查找效率也相对较高。

哈希表的构造

例如,这里有一个电话簿(查找表),电话簿中有 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