散列表

//尽可能让文章通俗易懂//

一、基本概念

散列表:通过将关键码映射到表中某个位置上来存储元素,然后根据关键码用同样的方式直接访问。

(根据给定的关键字来计算关键字在表中的地址

Hash(key)=Addr

通过散列函数建立了从元素关键码集合到散列表集合的一个映射。

由于关键码集合比散列表结合大得多,经过散列函数计算把不同关键码映射到同一个散列地址,这会产生冲突。

为了尽可能避免冲突要处理这两个问题:

(1)选择计算简单且地址分布均匀的散列函数

(2)拟定解决冲突的方案

二、常见散列函数

          构造散列函数应注意:

          1)函数定义域必须包括全部需要存储的关键字,而值域依赖散列表的大小或地址范围

          2)地址等概率均匀分布在整个地址空间

          3)函数尽量简单,计算地址时间

1.直接定址法

           直接取关键字的某个线性函数值为散列函数,散列函数为H(key)=a*key+b。适用于关键字分布连续的情况

          优点:简单,无冲突

           缺点:若关键字分布不连续,空位多,会造成存储空间浪费

例:hash(key)=key-940000

直接定址散列函数
序号0123456
关键字942148941269940527941630941805941558942047
散列地址214812695271630180515582047

2.除留取余法⭐⭐⭐

           已知散列表长为m,取一个不大于m但接近于m的质数p,利用公式H(key)=key%p  把关键字转为散列地址

3.数字分析法

             设有n个d位数,每一位可能有r种不同的符号,例如十进制数r=10。这r种不同的符号在各位出现的频率不一定相同。

若散列表的地址范围为[0...m-1],占d位数可选其中几种符号分布最均匀的d位,并乘以一个比例因子(m/r^d),把得到d位数压缩到0~m-1,从而得到记录的散列地址。

             适用于已知关键字集合。

序号关键码
0942148
1941269
2940527
3941630
4941805
5941558
6942047
7940001

可看到1、2、3 数字分布不均匀,4、5、6数字分布均与

4.平方取中法

             取关键字的平方值的中间几位作为散列地址。

            适用于关键字集合的每位取值不均匀或均小于散列地址所需的位数

5.折叠法

               将关键字分割成位数相同的几部分,然后取这几部分的叠加和作为散列地址

               叠加方法:(1)各部分最后一位相加   (2)各部分不折断,沿各部分的分界来回折叠,然后对齐相加,结果作为散列地址

———————————————————————————————————————————————————————

       上面介绍了几种散列函数,但是都有各自的缺陷,而且散列函数不可决定避免冲突。所以当有冲突时,如何为产生冲突的关键字寻找下一个空的hash地址  非常重要。

三、处理冲突的方法

1,开放定址法

                  指可存放新表项的空闲地址既向它的同义表项开放,又向它的非同义表项开放。数学递推公式为:H_{i}=(H(key)+d_{i})%m      其中i=0,1,2....k(k<=m-1);m表示散列表表长,di为增量顺序

               取定某一增量序列后,对应处理方法时确定的

(1)线性探测法

         使用某种函数计算出初始散列地址,当发生冲突时,在表中顺次向后寻找下一个空闲位置

   H_{i}=(H_{i-1}+1)%m

例如:有一组元素关键码为37,25,14,36,49,68,57,11,散列表为HT[12],表的大小为m=12,采用散列函数为Hash(x)=x%11

Hash(37)=37%11=4                  Hash(25)=25%11=3                 Hash(14)=14%11=3        Hash(36)=36%11=3

Hash(49)=49%11=3                  Hash(68)=68%11=2                 Hash(57)=57%11=2        Hash(11)=11%11=0

关键码3725143649685711
初始散列地址43335220
冲突散列地址-------3,43,4,55,6---2,3,4,5,6,7---
最后存入地址43567280
探测次数11343171

 

得到的散列表如图

1168253714364957    

查找成功的平均查找 长度为  查找到表中已有元素的平均探测次数,它是找到表中各个元素的探测次数的 平均值

查找不成功平均查找长度 为  表中查找不到待查元素,但找到插入位置的平均探测次数,它是要插入新元素时为找到空闲地址的探测次数的平均值,其设计范围包括散列函数可计算出的地址

(2)二次探测法

当di=0^2,1^2,-1^2,2^2,-2^2,...k^2时称为平方探测法,也称为二次探测法。

使用二次探测法在表中寻找下一个空闲位置的公式为H_{i}=(H_{0}\pm i^2)\%m 。m为表的大小,值为4k+3的素数

缺点是不能探测散列表所有单元,至少能探测一半

(3)再散列法

当di=Hash_{2}(key)

需要使用两个散列函数,

第一个函数得到的地址发生冲突时,利用第二个函数计算该关键字的地址增量。

H_{i}=(H(key)+i\times Hash_{2}(key))\%m

i是冲突次数,初始为0,最多经过m-1次探测遍历表中所有位置,回到H0位置

(4)伪随机序列法   当di=伪随机序列时,称为伪随机序列法

2.拉链法

       把所有同义词用线性链表存储起来,线性链表由其散列地址唯一标识,Hash存放得是相应同义词单链表的表头指针。

       假设散列地址为i的同义词链表的头指针存放在散列表的第i个单元中,因而插入、删除、查找主要在同义词链进行。

例如  关键字序列{19,14,23,01,68,20,84,27,55,11,10,79},散列函数H(key)=key%13

拉链法处理如图

四、散列查找以及性能分析

查找过程与构造散列表的过程基本一致。对于一个给定的关键字key,根据散列函数可计算出其散列地址。

步骤:初始化addr=has(key)

(1)检测查找表中地址为addr的位置上是否有记录,若记录,返回查找失败;若记录,与key比较,若想等,则返回查找成功标指,否则执行步骤(2)

(2)用给定的处理冲突方法计算下一个散列地址,并把addr置为此地址,转入(1)

查找效率:散列函数、装载因子、处理冲突的方法

装载因子\alpha =\frac{n}{m}  ,n为表中记录数,m为散列表长度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值