查找算法

查找表相关概念

查找表是由同一类型的数据元素(或记录)构成的集合。由于”集合”中的数据元素之间存在着完全松散的关系,因此查找表是一种非常灵便的数据结构。

静态查找表 static search table

动态查找表 dynamic search table

关键字 key 关键字是数据元素中某个数据项的值,用它可以标识一个数据元素。

静态查找表

顺序表的查找

顺序查找的过程:从表中的最后一个记录开始,逐个进行记录的关键字与给定的值进行比较,若某个记录的关键字和给定值比较相等,则查找成功。

小技巧:监视哨 在查找表的第一个记录中存储在要查找的值,则可以避免查找过程中每一步都要检测整个表是否查找完毕。
优点
算法简单且适应面广,对表的结构无任何要求。
缺点
平均查找长度较大。特别是当n很大时,查找效率较低,为(1+n)/2。

有序表的查找

  1. 折半查找
    先确定待查找记录所在的范围,然后逐步缩小范围直到找到或找不到该记录为止。
    折半查找的效率比顺序查找高,但折半查找只适用于有序表,且限于顺序存储结构(对线性链表无法有效地进行折半查找)
  2. 斐波那契查找
    1
    2
    3
    F0 =0,
    F1=1;
    Fi=F(i-1)+F(i-2);

斐波那契查找的平均性能优于折半查找,但是最坏情况下的性能却比折半查找差。O(logn),它还有一个优点就是分割时只进行加,减运算。

  1. 插值查找
    插值查找是根据给定值key来确定进行比较的关键字的查找方法。
    令i=(key-ST[l].key)(h-l+1)/(ST[h].key-ST[l].key)。
    其中ST[l].key和ST[h].key分别为有序表中具有最小关键字和最大关键字的记录。显然这种插值查找只适于关键字分布均匀的表,在这种情况下,对表长较大的顺序表,其平均性能比折半查找好。

静态树表的查找

前面对有序表的查找性能的讨论是在“等概率”的前提下进行的。但有序表中各个记录的查找概率不等式,则可以采用静态树表的查找。

如果只考虑查找成功的情况,则使查找性能达到最佳的判定树是其带权内路径长度之和PH值取最小的二叉树(静态最优查找树 static optimal search table)。
由于构建静态最优查找树花费的时间代价较高,因此仅介绍一种构造近似最优查找树(nearly optimal search table)的有效算法。

索引顺序表的查找

若以索引顺序表表示静态查找表,则查找可以用分块查找
分块查找又称为索引顺序查找,这是顺序查找的一种改进方法。在这种查找方法中,除表本身外,还需要建立一个“索引表”。将所有记录划分成多个子表,对每个子表建立一个索引项,其中包括两项内容:关键字项(保存该子表内的最大关键字)和指针项(指示该子表的第一个记录在表中的位置)。

动态查找表

动态查找表的特点是,表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回,否则插入关键字等于key的记录。

二叉排序树 binary sort tree

定义

  1. 若左子树不为空,则左子树上所有结点的值(关键字)都小于根结点的值;
  2. 若右子树不为空,则右子树上所有结点的值(关键字)都大于根结点的值;
  3. 左、右子树都分别是二叉排序树。

结论:若按中序遍历一棵二叉排序树,所得到的结点序列是一个递增序列。

平衡二叉树 AVL balanced binary tree

定义
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

  1. 红黑树
  2. AVL

    B-和B+树

    键树(数字查找树)

哈希表

哈希表的构造方法

  1. 直接定址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)。若其中H(key)中已经有值了,就往下一个找,直到H(key)中没有值了,就放进去。
  2. 数字分析法:分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。
  3. 平方取中法:当无法确定关键字中哪几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。
  4. 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。数位叠加可以有移位叠加和间界叠加两种方法。移位叠加是将分割后的每一部分的最低位对齐,然后相加;间界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。
  5. 随机数法:选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。
  6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

处理冲突的方法

  1. 开放定址法:Hi=(H(key) + di) MOD m,i=1,2,…,k(k<=m-1),其中H(key)为散列函数,m为散列表长,di为增量序列,可有下列三种取法:
    1.1. di=1,2,3,…,m-1,称线性探测再散列
    1.2. di=1^2,-1^2,2^2,-2^2,⑶^2,…,±(k)^2,(k<=m/2)称二次探测再散列
    1.3. di=伪随机数序列,称伪随机探测再散列
  2. 再哈希法:Hi=RHi(key),i=1,2,…,k RHi均是不同的散列函数,即在同义词产生地址冲突时计算另一个散列函数地址,直到冲突不再发生,这种方法不易产生“聚集”,但增加了计算时间。
  3. 链地址法(拉链法)将所有关键字为同义词的记录存储在同一线性链表中
  4. 建立一个公共溢出区,一旦冲突全部填入溢出表

参考资料

  1. 动态查找–二叉排序树
分享 留言