哈希查找算法

哈希查找算法利用哈希表进行高效查找,最佳情况下时间复杂度为O(1)。哈希表基于数组,通过哈希函数计算元素的存储位置。哈希冲突是常见的问题,可采用线性探测法等策略解决。本文通过例子展示了如何创建哈希表、解决冲突以及查找元素的过程。
摘要由CSDN通过智能技术生成

介绍:

哈希查找算法又称散列查找算法,是一种借助哈希表(散列表)查找目标元素的方法,查找效率最高时对应的时间复杂度为 O(1)。哈希查找算法既支持有序数列也支持无序数列,是比较高效的查找算法。

算法思想:

首先需要知道,哈希查找是在哈希表中来查找目标元素的,所以需要先创建一个哈希表,但是哈希表又是什么呢?哈希表是在数组的基础上构建的,


使用数组构建哈希表,最大的好处在于:可以直接将数组下标当作已存储元素的索引,不再需要为每个元素手动配置索引,极大得简化了构建哈希表的难度。

我们知道,在一个数组中如果我们知道了目标元素的在数组中的下标的话就会很容易的找到该元素,而哈希表的解决方案是:数组中的各个元素并不是按照数组的起始位置进行存储的,他们的下标而是按照已经设计好的函数计算出来的,这个函数就是哈希函数。

这个哈希函数就相当于数学中的一元一次方程一样,我们给它一个值,则它会返回一个值给我们,此时这个值就是该元素存储在哈希表中的下标。例如:将 {20, 30, 50, 70, 80} 存储到哈希表中,我们设计的哈希函数为 y=x/10,最终各个元素的存储位置如下图所示:

但是,这个时候就会又有疑问,假设我设计的哈希函数是y  = x % 10 怎么办呢?此时各个元素的存储位置就会是这样的:

 

 

此时一个下标中对应着多个元素, 这样存储位置就发生了冲突,我们就称这种状态为哈希冲突或者是哈希碰撞。所以此时也提供了一些解决方案:线性探测法,再哈希法,链地址法等。所以由此可以看的出来设计一个好的哈希函数可以减少哈希冲突的出现。

使用线性探测法解决哈希冲突的过程是:

  • 元素 5 最先存储到数组中下标为 5 的位置;
  • 元素 20 最先存储到数组中下标为 0 的位置;
  • 元素 30 的存储位置为 0,和 20 冲突,根据线性探测法,从下标为 0 的位置向后查找,下标为 1 的存储位置空闲,用来存储 30;
  • 元素 50 的存储位置为 0,和 20 冲突,根据线性探测法,从下标为 0 的位置向后查找,下标为 2 的存储位置空闲,用来存储 50;
  • 元素 55 的存储位置为 5,和 5 冲突,根据线性探测法,从下标为 5 的位置向后查找,下标为 6 的存储位置空闲,用来存储 55。

借助线性探测法,最终 {5, 20, 30, 50, 55} 存储到哈希表中的状态为:

假设我们从图 4 所示的哈希表中查找元素 50,查找过程需要经过以下几步:

  • 根据哈希函数 y=x%10,目标元素的存储位置为 0,但经过和下标为 0 处的元素 20 比较,该位置存储的并非目标元素;
  • 根据线性探测法,比较下标位置为 1 处的元素 30,也不是目标元素;
  • 继续比较下标位置为 2 的元素 50,成功找到目标元素。

代码展示:

#include <stdio.h>
#define N 10   //指定哈希表的长度
//自定义哈希函数
int hash(int value) {
    return value % 10;
}
//创建哈希表
void creatHash(int arr[5], int hashArr[N]) {
    int i,index;
    //将序列中每个元素存储到哈希表
    for (i = 0; i < 5; i++) {
        index = hash(arr[i]);
        while(hashArr[index % N] != 0) {
            index++;
        }
        hashArr[index] = arr[i];
    }
}
//实现哈希查找算法,hashArr 表示哈希表,value 为要查找的目标元素
int hash_search(int* hashArr, int value) {
    int hashAdd = hash(value);             //查找目标元素所在的索引
    while (hashArr[hashAdd] != value) {    // 如果索引位置不是目标元素,则发生了碰撞
        hashAdd = (hashAdd + 1) % N;       // 根据线性探测法,从索引位置依次向后探测
        //如果探测位置为空,或者重新回到了探测开始的位置(即探测了一圈),则查找失败
        if (hashArr[hashAdd] == 0 || hashAdd == hash(value)) {
            return -1;
        }
    }
    //返回目标元素所在的数组下标
    return  hashAdd;
}
int main()
{  
    int hashAdd;
    int hashArr[N] = { 0 };
    int arr[5] = {  };
    creatHash(arr, hashArr);
    hashAdd = hash_search(hashArr, 50);
    //如果返回值为 -1,表明查找失败,反之则返回目标元素所在的位置
    if (hashAdd == -1) {
        printf("查找失败\n");
    }
    else {
        printf("查找成功,目标元素所在哈希表中的下标为:%d", hashAdd);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

遇见陌生人了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值