数据结构复习七:查找算法之散列表的查找

一、散列表的基本概念

散列查找法(Hash Search)的思想是,在元素的存储位置和其关键字之间建立某种直接关系,这样在查找的时候就无需做比较,或者做很少次的比较,按照这种关系直接由关键字找到相应的记录。实际应用中通过对元素的关键字值进行某种运算,直接求出元素的地址,即使用关键字到地址的直接转换方法,而不需要反复比较。因此,散列查找法又叫杂凑法或者散列法
下面给出散列法中常用的几个术语:
(1)散列函数散列地址:在记录的存储位置p和其关键字key之间建立一个确当的对应关系H,使p=H(key),这个对应关系H为散列函数,p为散列地址。
(2)散列表:一个有限连续的地址空间,用以存储按散列函数计算得到相应散列地址的数据记录。通常散列表的存储空间是一个一维数组,散列地址是数组的下标。
(3)冲突同义词:对不同的关键字可能得到同一散列地址,即key1!=key2,而H(key1)=H(key2),这种现象称为冲突。具有相同函数值的关键字对该散列函数来说称作同义词,key1与key2互称为同义词。

散列查找法主要研究以下两方面的问题:
(1)如何构造散列函数;
(2)如何处理冲突。

二、散列函数的构造函数

构造散列函数的方法很多,一般来说,应根据具体问题选用不同的散列函数,通常要考虑以下因素:
(1)散列表的长度;
(2)关键字的长度;
(3)关键字的分布情况;
(4)计算散列函数所需的时间;
(5)记录的查找频率;
构造一个“好”的散列函数应遵循以下两条原则:
(1)函数计算要简单,每一关键字只能有一个散列地址与之对应;
(2)函数的值域须在表长的范围内,计算出的散列地址的分布应均匀,尽可能减少冲突。

1)数字分析法

如果事先知道关键字集合,且每个关键字的位数比散列表的地址码位数多,每个关键字由n位数组成,则可以从关键字中提取数字分布比较均匀的若干位作为散列地址。

2)平方取中法

通常在选定散列函数时不一定能直到关键字的全部情况,取其中那几位也不一定合适,而一个数平方后的中间几位数和数的每一位都相关,如果取关键字平方后的中间几位或其组合作为散列地址,则使随机分布的关键字得到的散列地址也是随机的,具体所取的位数由表长决定。

3)折叠法

将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址,这种方法称为折叠法。根据数位叠加的方式,可以把折叠发分为移位叠加和边界叠加两种。移位叠加是将分割后每一部分的最低位对齐,然后相加;边界叠加是将两个相邻的部分沿边界来回折叠(比如第一个数正着写,第二个数倒着写,第三个数正着写,以此类推),然后对齐相加。

4)除留余数法

假设散列表表长为m,选区一个不大于m的数p,用p去除关键字,除后所得余数为散列地址,即H(key)=key%p
这个方法的关键是选区适当的p,一般情况下,可以选p为小于表长的最大质数。

三、处理冲突的方法

1)开放地址法

基本思想:把记录都存储在散列表数组中,当某一记录关键字key初始开放地址H0=H(key)发生冲突时,以H0为基础,采取合适方法计算得到另一个地址H1,如果H1仍然发生冲突,以H1为基础再求下一个地址H2,以此类推,直至Hk不发生冲突为止,则Hk为该记录再表中的散列地址。
寻找下一个空位的过程称为探测,上述方法用公式表示为:Hi=(H(key)+di)%m   i=1,2,...,k(k<=m-1)
其中,H(key)为散列函数,m为表长,di为增量序列。根据di取值不同,可以分为以下3种探测方法:
(1)线性探测法:di=1,2,3,...,m-1;
(2)二次探测法:di=1^2,-1^2,2^2,-2^2,...,+k^2,-k^2(k<=m/2);
(3)伪随机探测法:di=伪随数序列。
处理冲突时,两个第一散列地址不同的记录争夺同一个后继散列地址的现象称作“二次聚集”(或称作“堆积”),即在处理同义词的冲突过程中又添加了非同义词的冲突。

2)链地址法

基本思想:把具有相同散列地址的记录放在同一个单链表中,称为同义词链表。有m个散列地址就有m个单链表,同时用数组HT[0...m-1]存放各个链表的头指针,凡是散列地址为i的记录都以结点方式插入到以HT[i]为头结点的单链表中。

四、散列表的查找

(以开放地址法为例)


存储表示:

#define m 20            //散列表的表长
typedef struct{ 
    KeyType key;        //关键字项
    InfoType otherinfo; //其他数据项
}HashTable[m];

算法步骤

(1)给定待查找的关键字key,根据造表时设定的散列函数计算H0=H(key)。
(2)若单元H0为空,则所查元素不存在。
(3)若单元H0中的元素的关键字为key,则查找成功。
(4)否则重复下述解决冲突的过程:
        1>按处理冲突的方法,计算下一个散列地址H1
        2>若单元Hi为空,则所查元素不存在
        3>若单元Hi中元素的关键字为key,则查找成功。

代码(伪):

#define NULLKEY=0
int SearchHash(HashTable HT,KeyType key){
    H0=H(key);
    if(HT[H0].key==NULLKEY) return -1;
    else if(HT[H0].key==key) return H0;
    else{
        for(i=1;i<m;++i){
            Hi=(H0+i)%m;
            if(HT[H0].key==NULLKEY) return -1;
            else if(HT[H0].key==key) return Hi;
        }
        return -1;
    }
}

注:本文所有内容均来源于《数据结构(C语言第二版)》(严蔚敏老师著)

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值