1.检索算法
1)顺序表和线性表方法
2)直接访问法(散列)
3)树索引方法
2.检索方法
1)对于已排序的顺序表,最好用的是二分搜索
2)词典检索(插值检索),像查词典一样,利用关键码的分布情况,首先在可能的范围中查看一个值,根据该位置的值决定下一次搜索的位置范围。
3)自组织线性表,一种非根据键值检索的方式。
按照数据被检索的频率排序,每次顺序查找,更新检索频率和重新排序。
自组织线性表的管理方式:
a. 计数方法
为每个记录保存一个访问次数,一旦此访问次数超过了前面的,就和前面的记录交换位置。问题在于如果一条记录曾经访问次数很多,但现在不再被访问了,它还是会在前面。
b. 移至前端法:一旦一个记录被访问到,就立即将其移动到表的最前端。这使得最近常被访问的记录都会一直在表的前面。这种方法会非常好的反应局部变化。
c. 转置法:将被访问的数据与其前面的记录进行交换,这使得常被访问的记录会不断前移,不再使用的则会慢慢落后。但是出现极端情况时,比如一直交替访问某两个相邻数据,这会使得他们谁也无法前移。
自组织线性表的应用举例:
消息压缩:比如,the car on the left hit the car I left.
压缩方式是,如果该单词未在线性表中出现,则完整写下该单词,否则写下该单词在线性表中的当前位置。线性表按照移至前端法进行组织。
如,前三个单词都为出现,于是按照原单词写下,线性表里的顺序则为:on car the
下一个单词是the,出现了,于是写下其位置3,且the要移动到前面,线性表变为the on car
接下来的left和hit都未出现,直接写下,在线性表中是:hit left the on car
下一个出现的单词又是the,于是写下其在表内的位置3,线性表变为:the hit left on car
下一个出现的是car,出现过了,于是写下它的位置5, 表序为:car the hit left on
第一次出现I,于是写下I,表内为:I car the hit left on.
最后出现的left是出现过的,写下其位置5,表为:left I car the hit left on.
压缩的结果就是the car on 3 left hit 3 5 I 5.
3.集合的检索
对于全部记录来说,可能不同的记录会属于不同的集合,比如0-100的数,有属于素数的,有属于奇数的。可用考虑在对应位置上存储一个bit,来表示其是否属于某集合。比如素数集合,对应的存储序列为0011010100,奇数集合存储的是0101010101,如果要求0-10上的奇素数,则将两个集合求交集即可:0011010100&010101010101
4.散列方法
根据关键码直接进行访问,把关键码映射到表中的位置。
散列表的关键在于不允许多个记录有相同的散列值,否则会造成冲突。
散列表的使用是为了节省空间和时间,为了实现随机访问,可将关键码的值作为数组下标进行存取,但是数组大小将取决于关键码的最大值,这不利于空间的使用。散列表中的槽数目肯定要比关键码的范围要小,但这也引出了一个新的问题,有些槽会被多个关键码映射到。
1)散列函数的选择
必须要选择能将记录合理的分配到散列表中的函数,至少一半以上的空间会被使用到且尽量无冲突。
2)冲突解决技术
1)开散列办法(单链方法)
开散列的开是指将冲突的记录存储在表外,相对的还有闭散列方法,将冲突的记录存储在表内。
a.链表方法:每一个槽定义为一个链表表头,后面跟着同样映射到该槽内的记录。
2)闭散列方法(开地址办法)
1)桶式散列
将散列表分成多个桶,每个桶内若干个槽。散列函数将每条记录分配到对应桶中的第一个空槽中。如果桶满了,则放在一个外部的公用无限溢出桶中。
2)线性探查技术与聚集问题
意思是如果散列的槽中已经放了数据,则从基位置开始线性探查,找一个空位置放该条记录。
这种办法容易造成概率不均,比如说,一个模11的函数作为哈希函数,当第0,1,2个位置都被占用,其他位置空余时,此时再来任何数,放到第3个位置的概率是4/11,而放到其他未被占用的槽中的概率是1/11.这导致了基本聚集(相邻的记录的探查序列相同)。
探查方式:每个探查序列不按照1步进行探查,而是按照c步探查,即每次不是查看下一个槽是否为空,而是下面第c个槽,以此类推。 这种方法需要保证c与散列表的长度M是互质的,才能使得所有探查序列都能够走过每个槽。以c>1的步数进行探查并不能解决基本解决问题,比如c=2时,1和3的探查序列将完全相同。
伪随机探查:生成一个伪随机数列r,ri的值在1 - M-1之间,每次探查都使用这个探查序列。比如一个3,4,5 的随机序列,如果要对槽1和槽3进行探查,他们分别的探查序列为,(1,4,8,13)和(3,6,10,15)显然是分开的,消除了基本聚集。
二次探查:二次探查也能避免基本聚集,它是用i^2作为探查步数来的。
伪随机探查和二次探查遗留的问题:如果两个关键码散列到同一个 位置,这二者的基位置就一样了,所以探查序列也就一样了。这个是二级聚集。
二级聚集:解决办法,使得探测函数不是基位置的函数,而是关键码的函数。一种简单做法是使得探查函数的常量依赖于另一个基于关键码的散列函数,这种方式称为双散列方法。
5.散列方法的效率问题
散列法随着散列表的负载的升高,各种操作的代价也会随之增加。