查找操作-----常数查找

查找操作—–常数查找(哈希查找)

对于很多人来说,折半查找的对数级O(logn)时间复杂性是可以接受的。问题是,折半查找虽然有着对数级的时间复杂性,但它只能用在有序序列上。而对数列的排序需要(nlogn)的时间。

常见的几种排序算法(java和C++版)(参考《算法》)

一个这样一来折半查找的综合成本实际上是高于O(logn)的。更严峻的是,查找问题通常具有两个特点:一是查找的范围很大;二是查找是一个频繁的操作,即经常要执行的操作。这样,O(logn)级的时间复杂性就显得有点高了。因为如果n非常大,logn也还是会很大。而如果查找执行的频率又很高,则查找的总成本就相当可观了。

因此,探索更有效的查找方法就是一件非常有必要的事情。仔细分析查找问题可以发现,我们并不需要知道要查找的元素与其他元素的关系,即在查找元素x时,并不需要知道x和其他元素究竟处于什么位置,或者有多少元素比x小(大)。也就是查找一个元素只与该元素自己有关,并不涉及其他元素。所以从理论上讲,应该可以设计出常数时间的查找方法。到目前为止,设计的查找方法之所以达不到常数级并不是查找问题本身的理论现在,而是设计的思路有问题。

有一个司空见惯的场景:当去某公司拜访客户时,前台接待人员会熟练地拨通该客户的电话询问并作出相应安排,而无需查询该客户的电话。而无需查询客户的电话。

从查询的角度看,前台接待人员在查找客户的电话是,用的就是常数时间。即想办法记住每个元素所在的位置。这种记住每个元素所在位置的额查找方法就是所谓的常数查找。

在计算机时间常数查找的办法有两种:直接查找和间接查找。

直接查找

直接查找就是根据其索引直接定位到其所在的位置。由于所有的数据都可以表示为数,只要将每个数据存放在以其值为索引的位置上,就可以轻而易举地时间直接查找。例如,对于数值为3的元素,其存放在位置为3的地址上。
直接查找虽然成本为常数,但有一个很大的缺点:需要的空间可能巨大。例如,如果处理的数据取值可能达到1千万,则存放数据的空间就需要有1千万的容量。如果需处理的数据总量很少,如100个数据项,这样为了能够为100个数据项提供直接查找操作,则需要耗费1千万的存储空间,这是非常不划算的。

间接查找

解决的办法就是间接查找:将数据项的取值大小与存储位置的直接联系斩断,同时,在他们之间增加一个间接的联系纽带,使得用户仍然可以根据数据项的取值迅速找到其存放的位置。则个间接的纽带通常是一个函数。将数据项的值代入到一个函数,计算出的结果就是该数据所在的存储位置。这就是间接查找,也成为哈希查找。

简单地讲,间接查找是通过某种函数将数据元素映射到一个特定的位置,如数组的索引上。这个映射函数称为哈希函数。这个数组称为哈希表。在需要查找某个数据元素时,只需要将元素作为变量代入到哈希函数里。即可求得该数据元素所在的哈希表索引,从而找到该数据元素。如果对于该索引的哈希表项的内容为空,则说明该记录不存在。哈希插入操作同样简单:将需要被插入的数据元素作为变量值带入到哈希函数中,即可求得该数据元素所应当插入的哈希表的位置。

在这种操作模式下,空间的使用与数据项的取值没有关系,,而只是与要处理的数据量有关。
要实现哈希查找,就需要设计一个哈希函数,每个元素在表中的位置由该函数确定。

int list::hash_insert(const int &x,int &position)       //哈希插入
{
    int i = x % maxlist;            //哈希函数,最简单的求模运算
    if(data[i] == 0)
    {
        data[i] = x;
        position = i;
        return success;
    }
    else
        return overflow;
}
int list::hash_find(const int &x,int &position)         //哈希查找
{
    int i = x % maxlist;            //哈希函数,应与插入函数使用的是同一个函数
    if(data[i] = x)
    {
        position = i;
        return success;
    }
    else
        return overflow;
}

大家可能注意到,在上面的哈希插入和哈希查找方法里,使用的哈希函数非常简单:模运算。在插入过程中,对待插入元素x进行模运算求得其应该存放的位置。如果该位置上没有元素,则将x存入该位置;否则发生溢出,在哈希术语中称为碰撞。
在上述实现中仅仅是报告溢出错误,并没有采取手段来解决碰撞。我在下次写一些关于哈希函数产生碰撞时的处理方式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值