Hash表的“查找成功的ASL”和“查找不成功的ASL”
ASL指的是 平均查找时间
关键字序列:(7、8、30、11、18、9、14)
散列函数:
H(Key) = (key x 3) MOD 7
装载因子:
0.7
处理冲突:线性探测再散列法
查找成功的ASL计算方法:
以下求解过程是按照“计算机统考的计算方法”,不同的老师、教材在“处理冲突”上可能会有不同的方法,所以最主要的是掌握原理即可,对于考研的朋友最好掌握统考真题的解题方法。
题目
例子:(2010年全国硕士研究生入学统一考试计算机科学与技术学科联考计算机学科专业基础综合试题第一题)
将关键字序列(7、8、30、11、18、9、14)散列存储到散列表中。散列表的存储空间是一个下标从0开始的一维数组。散列函数为: H(key) = (keyx3) MOD 7,处理冲突采用线性探测再散列法,要求装填(载)因子为0.7。
(1) 请画出所构造的散列表;
(2) 分别计算等概率情况下查找成功和查找不成功的平均查找长度。
1.散列表:
α = 表中填入的记录数/哈希表长度 ==> 哈希表长度 = 7/0.7 = 10
H(7) = (7x3) MOD 7 = 0 H(8) = (8x3) MOD 7 = 3 H(30) = (30x3) MOD 7 = 6
H(11) = (11x3) MOD 7 = 5 H(18) = (18x3) MOD 7 = 5 H(9) = (9x3) MOD 7 = 6
H(14) = (14x3) MOD 7 = 0
按关键字序列顺序依次向哈希表中填入,发生冲突后按照“线性探测”探测到第一个空位置填入。
因为现在的数据是7个,填充因子是0.7。所以数组大小=7/0.7=10,即写出来的散列表大小为10,下标从0~9。
第一个元素7,带入散列函数,计算得0。
第二个元素8,带入散列函数,计算得3。
第三个元素30,带入散列函数,计算得6。
第四个元素11,带入散列函数,计算得5。
第五个元素18,带入散列函数,计算得5;此时和11冲突,使用线性探测法,得7。
第六个元素9,带入散列函数,计算得6;此时和30冲突,使用线性探测法,得8。
第七个元素14,带入散列函数,计算得0;此时和7冲突,使用线性探测法,得1。
所以散列表:
地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
key | 7 | 14 | 8 | 11 | 30 | 18 | 9 | |
2.查找长度:
2.1 查找成功的平均查找长度
(待查找的数字肯定在散列表中才会查找成功)
查找数字A的长度 = 需要和散列表中的数比较的次数;
步骤:
比如 查找数字:8
则 H(8) = (8x3) MOD 7 = 3
哈希表中地址3处的数字为8,进行了第一次比较:8 = 8,则查找成功,查找长度为1;
比如查找数字:14
则 H(14) = (14x3) MOD 7 = 0
哈希表中地址0处的数字为7,进行第一次比较:7≠14
哈希表中地址1处的数字为14,进行第二次比较:14=14 ,则查找成功,查找长度为2。
由此可得到如下数据:【2016年12月26日修改,多谢@一楼的朋友指正】
0 1 2 3 4 5 6 7 8 9
7 14 8 11 30 18 9
1 2 1 1 1 3 3
所以总的查找成功的平均查找长度= (1+1+1+1+3+3+2)/7 = 12/7
2.2查找不成功的平均查找长度
(待查找的数字肯定不在散列表中)
【解题的关键之处】根据哈希函数地址为MOD7,因此任何一个数经散列函数计算以后的初始地址只可能在0~6的位置
查找0~6位置查找失败的查找次数为:
地址0,到第一个关键字为空的地址2需要比较3次,因此查找不成功的次数为3.
地址1,到第一个关键字为空的地址2需要比较2次,因此查找不成功的次数为2.
地址2,到第一个关键字为空的地址2需要比较1次,因此查找不成功的次数为1.
地址3,到第一个关键字为空的地址4需要比较2次,因此查找不成功的次数为2.
地址4,到第一个关键字为空的地址4需要比较1次,因此查找不成功的次数为1.
地址5,到第一个关键字为空的地址2(比较到地址6,再循环回去)需要比较5次,因此查找不成功的次数为5.
地址6,到第一个关键字为空的地址2(比较到地址6,再循环回去)需要比较4次,因此查找不成功的次数为4.
于是得到如下数据:
0 1 2 3 4 5 6 7 8 9
7 14 8 11 30 18 9
3 2 1 2 1 5 4
则查找不成功的平均查找长度 = (3+2+1+2+1+5+4)/7 = 18/7
二.hash算法原理详解
一.概念
哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。
哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。
使用哈希查找有两个步骤:
1. 使用哈希函数将被查找的键转换为数组的索引。在理想的情况下,不同的键会被转换为不同的索引值,但是在有些情况下我们需要处理多个键被哈希到同一个索引值的情况。所以哈希查找的第二个步骤就是处理冲突
2. 处理哈希碰撞冲突。有很多处理哈希碰撞冲突的方法,本文后面会介绍拉链法和线性探测法。
哈希表是一个在时间和空间上做出权衡的经典例子。如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1);如果没有时间限制,那么我们可以使用无序数组并进行顺序查找,这样只需要很少的内存。哈希表使用了适度的时间和空间来在这两个极端之间找到了平衡。只需要调整哈希函数算法即可在时间和空间上做出取舍。
在Hash表中,记录在表中的位置和其关键字之间存在着一种确定的关系。这样我们就能预先知道所查关键字在表中的位置,从而直接通过下标找到记录。使ASL趋近与0.
1) 哈希(Hash)函数是一个映象,即: 将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地 址集合的大小不超出允许范围即可;
2) 由于哈希函数是一个压缩映象,因此,在一般情况下,很容易产生“冲突”现象,即: key1!=key2,而 f (key1) = f(key2)。
3). 只能尽量减少冲突而不能完全避免冲突,这是因为通常关键字集合比较大,其元素包括所有可能的关键字, 而地址集合的元素仅为哈希表中的地址值
在构造这种特殊的“查找表” 时,除了需要选择一个“好”(尽可能少产生冲突)的哈希函数之外;还需要找到一 种“处理冲突” 的方法。
二.Hash构造函数的方法
1.直接定址法:
直接定址法是以数据元素关键字k本身或它的线性函数作为它的哈希地址,即:H(k)=k 或 H(k)=a×k+b ; (其中a,b为常数)
例1,有一个人口统计表,记录了从1岁到100岁的人口数目,其中年龄作为关键字,哈希函数取关键字本身,如图(1):
地址 |
A1 |
A2 |
…… |
A99 |
A100 |
年龄 |
1 |
2 |
…… |
99 |
100 |
人数 |
980 |
800 |
…… |
495 |
107 |
可以看到,当需要查找某一年龄的人数时,直接查找相应的项即可。如查找99岁的老人数,则直接读出第99项即可。
地址 |
A0 |
A1 |
…… |
A9 |