检索的平均检索长度(ASL(Average Search Length))计算公式
A S L = ∑ i = 1 n p i ∗ c i ASL=\sum_{i=1}^{n}p_{i}*c_{i} ASL=i=1∑npi∗ci
p i p_i pi 是检索到的概率 c i c_i ci 检索长度
直接将插入元素放入线性表后面,最基本的存储方式。
每次检索都的概率都相同1/n,检索长度和为(1+2+3+…+n),公式计算结果为(n+1))/2
检索用的复杂度为: O ( n ) O(n) O(n)
这种结构导致在动态字典的各种操作中效率不变,也是效率最低操作。
数据线性表采用二分法,可以了解到查找的复杂度为 O ( l o g 2 n ) O(log_2 n) O(log2n)。
顺序线性表的插入和删除都需要将数据移动,所以复杂度为 O ( n ) O(n) O(n)
以上两种方式为基本的存储方式,在面临大数据及和动态数据集的时候检索效率较低,解决这个问题主要采用了以下两种结构
散列的基本思想是:如果关键码不能或者不适合作为数据存储的下标可以考虑通过一个变换,把它映射到一种下标。
通常情况下,散列的key值范围远远大于下标范围。直接导致在散列的过程中会出现散列之后会相同的情况。
对于规模固定的散列表,表中元素越多产生冲突可能性越大,使用参数使用负载因子 α \alpha α进行衡量
负 载 因 子 α = 散 列 表 中 实 际 数 据 数 量 散 列 表 容 量 负载因子\alpha=\frac{散列表中实际数据数量}{散列表容量} 负载因子α=散列表容量散列表中实际数据数量
α \alpha α越大则冲突可能性越大。 α \alpha α无论大小都会导致散列冲突。
优化冲突的首先想到的是采取的是优化散列函数的方式。
散列函数的作用是将关键值映射到指定的下标范围内,散列函数设计的优劣直接影响冲突发生的概率。着重考虑一下三点:
在已知关键码的情况下,可能设计出最合适的散列函数。
以下是几种关于证书关键码的散列方法:
数字分析法:在给定数据关键码的情况下,分析数据中数字出现的频率,选取分布较好的作为散列方法,如选取十位和百位数据作为散列方法。
折叠法:将较长的关键字分成几段,通过运算将其合并。如将10位整数按三位拆分,进行加和,再舍弃进位,就可映射到[0, 999]区间了。
中平方法:想求出关键码的平方,然后取出中间的几位作为散列值。
通用的散列方法只适用于均匀分布假设,以下两种通用的散列函数:
除余法:使用key除以某个不大于散列长度m的整数p,得到某个余数(或加上某值)作为散列地址。一般m取2的整数次幂。
基数转换法:整数关键码。将关键码看做是r进制的数值,转换成想要转换的进制,通常取r为素数。若范围不合适,使用以上方法映射到指定区间。如果字符串,可将字符转换成整数编码。
通过合理的hash函数尽量避免冲突,但解决不了冲突。通常采用两种方式化解冲突。
处理冲突的两个基本要求:
内消解的基本方法是开地址法。基本思想是插入数据发现冲突时,另行安排一个位置。为此方法设计的位置安排方式,称为探查方式。
内消解法的主要原理是如果遇到散列冲突后,查找其它位置进行填充,这种方式成为探查方式。定义:
D = d 0 , d 1 , d 2 ⋯ D=d_0, d_1, d_2\cdots D=d0,d1,d2⋯
定义探查序列为
H i = ( h ( k e y ) + d i ) m o d p H_i=(h(key)+d_i)\,mod\,p Hi=(h(key)+di)modp
d i d_i di 增量的设计有多种设计:
1. 线性探查:取连续的探查间隔,D = 0,1,2,…,当有冲突之后一次探查后面位置是否占用
2. 双散列探查:设计散列函数h2,令 d i = i × h 2 ( k e y ) d_i= i×h_2(key) di=i×h2(key)。有冲突后探查 h 2 h_2 h2散列后的整数倍2位置是否被占用。
检索
1. 调用散列函数,算出key值
2. 查看存储位置,若没有数据则不存在
3. 若相等,则存在
4. 若不等则,进行探查,回到2
删除
删除注意问题:可能删除元素在检索路径上,则需在删除后添加标记元素占位。
设置另一个存储区,当有冲突时,按顺序将溢出区结果存入存储区。在冲突较少的情况下效果较好。
将散列后的index值存放一个引用,每个位置设置为一种数据结构,可使用链表进行实现,插入时可先检索散列后的位置链表是否存在该元素,检索删除对应位置链表元素。
可用于大型字典的实现。
无论那种方法,由于散列的基本原理。随着元素的增加都会导致负载因子增大,冲突概率增大。
开地址随着数据增加导致溢出;拉链法会增加链的平均长度。
采用内部消解技术(开地址)时,负载因子 α \alpha α<=0.7~0.75,检索效率越来越趋于线性;在桶散列技术中,负载因子 α \alpha α就是桶的平均长度。
人们说散列是一种搞笑的字典实现技术,是有些基本假设条件的:
满足这些条件,散列表检索、插入、删除的时间开销可以看作常量。
散列字典从概率上讲极为高效,但事情也有另一面:
还有可能出现不好情况:
实际实现中,可能需要考虑许多问题: