检索笔记摘要

  今天回顾了一下检索部分的内容,写在这里和大家分享,有错误的地方请不吝指正。(挑一些觉得重要的点讲)

 

  1、 考虑在线性表和散列表上的检索

  2、 用ASL来表示检索的平均效率,要考虑失败和成功两种可能

  3、 基于线性表的检索:

    1) 顺序检索:对于一个有n元素的线性表,成功为, 失败为(设置了一个监视哨),平均为

    2) 二分检索:前提条件是线性表有序,复杂度为,伪代码:

def binarysearch(L, s, e, key):

    while s <= e:

        mid = (s + e) // 2

        if L[mid] < key:

            s = mid + 1

        elif L[mid] > key:

            e = mid - 1

        else:

            return mid

return -1

    要注意的一个问题是,对于一个长度为n的线性表,失败的检索长度为的上取整或者下取整,可以自己画图看一下;成功的检索平均长度也是在这个量级,自己估计,注意求和的方法,缺点是不易更新且要排序

    3) 分块检索:块内无序,块间有块(前一个块的最大值<后一个块的最小值)

    需要一个索引表(存每个块的最大值,下标,对应块中元素个数)来辅助查找,设有b个块,每个块平均s个元素,若全部都是用顺序查找的话,b = s = sqrt(n)的时候效率最高,ASL = sqrt(n),不难发现缺陷。

  4、 散列表:从数组寻址找到的灵感,从要寻找的关键码直接对应到地址。负载因子a = N/M,一般来说a的范围是[0,1](开散列其实不受限制),问题:如何“散列”、如何解决冲突。

  5、 直接求余数法、乘余取整法、平方取中法、数字分析法(考虑某一位的分布均匀性,取出若干位分布均匀的作为地址)、基数转换法、折叠法

  6、 冲突解决方法:开散列(负载因子不受限制,但一般也是0~1)/闭散列

  7、 开散列比较适用于记录可以存在内存的情况,因为如果存在外存且使用拉链法的话,有同义词的话可能会存在不同的磁盘页里导致I/O次数变大。所以用桶散列的方法来解决相关的外存问题。但是开散列中,拉链法适合不定长的情况,而且删除方法比较容易实现

  8、 闭散列中,设关键码为k, 则h(k)为基地址,p(k,i)表示第i次查探的地址偏移量

    di = d0 + i * p(k,i) 表示查找序列中的第i个地址

  9、 对于p(k,i)取不同的函数有线性探查法、改进的线性探查(i*c)、二次探查法、伪随机探查法。

  10、基本聚集:基地址不同的关键码的探查序列重叠在一起(用二次探查法或者伪随机可以较好的解决);二次聚集:基地址相同的关键码的探查序列重叠在一起(因为探查序列只是基地址的函数,和关键码无关)。

  11、为了解决二次聚集的情况,考虑用双散列方法,也就是让探查序列变成与关键码有关的函数。用h1(key)生成基地址,h2(key)表示每次要跳过的常数项记录,h2(key)必须和模数M互素,计算量比较大,但是冲突少。

  12、自己编写一个数据结构来实现哈希表的功能。

  插入:若探查序列中当前项不是空,如果等于待插入记录就返回false(不允许相同记录存在),否则就找下一个记录直到一个空的位置插入。

  查找:比较简单,略去

  删除:不能真正的删除,要考虑到这个位置可能在其他的探查序列里面,所以要分开记录“已删除”、“已占用”、“空”这三种状态,“已删除”的记录可以用来插入和查找、“空”的记录可以用来插入、“已占用”的记录可以用来“查找”、“删除”。

  我们可以用一个“墓碑”来表示被删除的记录位置,删除的算法没有太大变化,但是在插入中要小心:由于不能重复插入记录,所以我们碰到墓碑时先记录下第一个待插入的墓碑,再检查后面的记录有没有出现相同记录,当然也可能插入在空的位置。伪代码如下:

def tomb_insert(e):  

    i = insplace = 0, pos = home = h(getkey(e))

    tomb_pos = False

    while !eq(EMPTY, HT[pos]):

        if eq(e, HT[pos]):

            return False #出现了相同记录,不插入

        elif eq(tomb, HT[pos]) and !tomb_pos:

            tomb_pos = True

            insplace = pos

        i += 1

        pos = (home + p(getkey(e), i)) % M

    if tomb_pos == False:

        insplace = pos

    HT[insplace] = e

      return True

  13、关于散列效率的分析,见下表:具体推导见算法导论(如果有时间看就尽力补上)

 

  14、散列方法在负载因子大约为0.5时效率比较高,大于这个临界值时效率会急剧下降

posted @ 2019-12-23 10:34  一笑正中双飞翼  阅读(196)  评论(0编辑  收藏  举报