检索(散列)

来源:互联网 发布:plc网络传输器弊端 编辑:程序博客网 时间:2024/06/10 10:19

检索算法分类:

  1. 顺序表和线性表法
  2. 根据关键码值直接访问方法(散列表)
  3. 树索引方法

顺序检索

(关键码值按大小排序)
最基础的检索算法,但是遇到重复查找的庞大记录集合,顺序检索会慢到令人无法忍受。一般常用的索引方式是二分查找

自组织线性表

由于线性表大多数情况下是使用关键码进行顺序排序的,但是这对于一些特定情况将会减慢搜索速度,例如某一关键码时常出现,但是它又在线性表的末端,这样每次都得执行到末端才能访问到,因此自组织线性表应运而生。

它显著优于排序算法的地方在于不用对线性表进行排序操作,这意味着插入一条新纪录的代价很低,当需要频繁插入记录时,这补偿了检索的高代价。自组织线性表比检索树更容易实现

管理自组织线性表的常见的3种启发式规则:

  1. 频率计算(类LFU):用额外的空间存储线性表中各个元素被访问的次数,并按访问次数对线性表进行排序,这种方式的缺点是一段时间内访问次数最多的记录,即使后来都没出现该条记录的访问,在后面的很长一段时间都在最前面。
  2. 移至前端(类LRU):每次访问某条记录时,如果线性表中有该条记录,则将记录提到最前面,原位置前的记录往后挪位;如果没有该条记录,则将其插入到最前面,其他位置往后挪位。这种算法虽然解决了频率计数的滞留问题,但也有明显的缺点,例如当
  3. 转置(transpose):把找到的记录与它在线性表中的前一条记录交换位置。曾经被频繁访问但是以后不再使用的记录将会慢慢的落到后面。但是如果出现交替访问相邻的末端记录,如相邻记录Y、X在线性表的末端,访问顺序为XYXYXYXY,则记录X、Y将一直互相交换位置,但是两条记录都不能向前移动。

集合检索

可以用于文档检索,例如对于每个关键字,文档检索系统存储一个位向量,每个文档一位。如果用户想要知道哪些文档中包含某三个关键字,就把相应的3个位向量进行AND操作,结果位置上值为1的位就对应符合要求的文档。


散列方法

散列方法通常不适用于多条记录含有相同关键码的应用程序

对于关键码值是数字的情况,有一种散列方法很合适,就是平方取中法:计算关键码值的平方,去除结果的中间r位,给定范围为从0~2^r-1的值

过程:
1. 计算表的位置h(K)
2. 从槽h(K)开始,使用(如果需要)冲突解决策略找到包含关键码值K的记录

开散列(把冲突记录存储在表外):

这种方式一般用于主存中而不用于磁盘,因为一个链表中的多个元素可能存储在不同的磁盘块上,这就导致检索一个关键码需要多次磁盘访问,从而低效了散列方法的好处

闭散列(把冲突记录存储在表中的另一个槽里):

  1. 桶式散列

    • 把散列表中的M个槽分为B个桶,每个桶中包含M/B个槽,在查找或插入时,如果对应的桶被占满,则将从溢出桶里查找或插入,注意:所有的桶共享一个溢出桶
    • 桶式散列适用于实现基于磁盘的散列表,因为可以把同的大小设置为磁盘块的大小,每当进行检索或插入时,就把整个桶读入内存。
  2. 线性探查

    在此之前先了解一下概念:
    基槽:关键码通过散列函数h(x)映射到的槽称为该关键码的基槽
    基本聚集:多个关键码值在线性探查过程中找到的探查序列的某些段重叠在一起,例如:探查序列1{3,5,7,9},序列2{5,7,9,11}

    • 与桶式的不同,该种方式是最为常用的散列方法,他的冲突解决策略可以使用散列表的任何一个槽。
    • 查找方式是:当根据散列函数h(x)散列到的基槽已经被占用时,将根据探查函数p(K,i)查找下一个槽,直到找到对应的关键码【其中i探查序列中的期望位置,p(K,i)返回的是到基槽的偏移量 】
    • 因此找到一个适合的探查函数十分重要,否则将会导致基本聚集这一问题的出现。
      常见的有几种解决方法:
      1. 伪随机探查:将一组随机数存放在一个数组中,然后i选择数组中的元素
      2. 二次探查:探查函数为2次方程,例如:p(K,i)=i^2
      3. 双散列探查:当散列函数在某个基槽聚集时,那么伪随机探查和二次探查仍然会保持聚集,因此如果探查函数将关键码值考虑进去的话就能够避免。例如:p(K,i)=i*h2(K),其中h2为另一散列函数。
    • 散列元素的删除
      散列元素在删除时不能简单的把槽标记为空,因为这样会断开探查序列后面的记录。因此引入“墓碑”这一概念。

    墓碑:标志一条记录曾经占过这个槽,现已被删除,在检索时如果遇到墓碑,将沿着探查序列继续检索;在插入时如果遇到墓碑,为了防止插入相同的关键码导致散列中有重复的关键码,这个时候继续往后走下去,直到找到一个真正的空位并没有查找到要插入的关键码值,然后新纪录插到之前遇到的的墓碑标记的槽中

0 0
原创粉丝点击