1.5查找

1.5查找

查找是重要的一种操作,又称为检索。查找的对象既可以是线性表,也可以是树形结构,甚至是文件结构。

查找的主要方式有顺序查找,折半查找,基于树形结构的查找即散列法。

1.5.1查找的基本概念

关键字是数据元素中某个数据项的值,用它可以标识一个数据元素。能够唯一表示一个数据元素的关键字成为关键字,用来标识若干各数据元素的关键字称为次关键字。或者说,对任一值value,查找表中最多只能有一个记录的主关键字是value,但次关键字为value的记录可能有多个记录。

根据给定的某个值key,在查找表中寻找关键字Ki=key的记录的过程称为查找,也称为检索。若查找表中存在这样的记录,称查找成功;否则称查找失败,即查找表中不存在关键字为key的记录。key称为查找目标。

查找过程中,关键字的比较次数称为查找长度。使用查找成功时平均查找长度(ASL)及查找不成功时查找长度来衡量查找算法的效率。

1.5.2 顺序查找法

若查找表中关键字无序,则可使用顺序查找法。

顺序查找的策略非常简单:从K0开始,将查找目标依次于关键字进行比较,若相等,则查找成功;否则继续比较下一个关键字。当查找表中所有关键字都与查找目标进行了比较且全不相等时,查找失败,查找过程结束。

在含n个元素的查找表中,查找不成功时的查找长度为n。查找成功时的查找长度要依赖于查找目标在查找表中所处的位置。当查找目标位于查找表第一个位置时,比较依次即可找到目标,查找长度为1;当查找目标位于查找表最后一个位置时,比较依次即可找到目标,查找长度为1;当查找目标位于查找表最后一个位置时,需要比较n次才能找到目标,查找目标为n;平均查找长度为(n+1)/2。

顺序查找法的查找表既可以是数组,也可以是链表。甚至是文件。查找表中各记录的关键字不要求有序。

1.5.3折半查找法

在无序查找表上查找效率不高,等效率查找情况下平均查找长度为(n+1)/2。

如果查找表有序,可以采用折半查找法,有效提高查找效率。

折半查找法也称为二分查找法,它利用查找表的有序性,采用”分治“策略,先确定查找目标所在的范围,之后的每次比较都能使查找表缩小一般的范围,直到找到查找目标,或是待查范围为空时为止。

比较A[mid]与查找目标,分以下几种情况:

  • A[mid]=key, 查找成功;

  • A[mid]>key,high=mid,在查找范围内继续查找;

  • A[mid]

    当low>high时,查找范围为空,没有元素可检查,查找表中没有查找目标,查找失败。

    第一趟查找:mid=(8+0)/2=4,检查a[4]

    第二趟查找:mid=(0+3)/2=1,检查a[1]

    第三趟查找:mid=(2+3)/2=2,检查a[2],找到Key

    折半查找过程中,关键字比较序列实际上是从根到某个叶结点路径上的关键字序列中的一部分。

    求中间位置时可能会出现取整操作,此时即可以上取整,也可以下取整。一旦确定下来,整个查找过程中必须一致。在例1-2中,若mid=[(low+high)/2],则对应的判定树如图1-28所示。

1.5.4 分块查找法

分块查找要求把一个大的查找表分成若干块,每块中的值无序,但块与块之间必须有序,即整体有序。

对于任意的i,第i块中所有的关键字都小于第i+1块中素有的关键值.此外,还要建立一个索引表,把每块中的最大关键字作为索引表的关键值,按块的顺序保存在一个一维数组中,且数组按关键值有序。

查找时,首先在索引表中进行查找,确定要找的关键之所在块。然后再相应的块中进行查找。

虽然索引表占据了额外的存储空间,索引表的查找也增加了一定的系统开销,但因为将查找表惊醒分块,使得再块内查找时,查找范围缩小,与顺序查找法相比,效率提高。

1.5.5B树机器基本操作,B+树的基本概念

1.B树的基本概念

1970年Bayer等人提出一种多路平衡查找树,称为B树。它的定义如下:

一棵M阶B树或者为空,或者为满足下列性质的M叉树:

  1. 树中每个结点至多有m颗子树
  2. 根结点至少有两颗子树
  3. 除根结点之外,每个结点至少有[m/2]棵子树
  4. 所有叶结点都出现在同一层上;
  5. 所有结点都包含如下形式的数据:(n,A0,K1,A1,K2,A2,…,Kn,An)

其中n为关键字的个数,Ki(i=1,…,n)为关键字,且满足K1

如图1-29所示的是一颗5阶(m=5)B树。

当m=3时,每个结点中最多包含两个关键字,三个指针,最少时可以只含有一个关键字,两个指针,所以3阶B树又称为2-3树。

1.5.6 散列(Hash)表

顺序查找,分块查找,折半查找及树形结构中的查找等,都是基于关键字的”比较“操作。散列查找是一种拜托”比较“操作的查找方法。散列在关键字值及其存储位置之间建立某种关系,基于关键字值完成记录的访问。即包括数据元素的存储过程,也能实现数据元素的查找过程。关键字值与其存储位置(称为哈希地址)之间的关系由散列函数(或哈希函数)给出,保存记录的查找表也称为散列表(哈希表)。采用散列函数在散列表中进行的查找方法称为散列方法(或哈希方法)。

1.哈希函数

哈希函数是一个映射关系,它将关键字映射到哈希地址,表示为:addr=H(key),其中addr是元素key在哈希表中哈希地址。影响哈希函数喧杂的因素包括计算哈希函数所需的时间,关键字的长度,哈希表的大小,关键字的分布情况及记录的查找频率。若两个关键字映射到同以哈希地址,称为”冲突“。将每个关键字映射到哈希表中唯一位置的哈希函数称为完美哈希函数(perfect hashing function)。完美哈希函数不会引起冲突,在这种情况下,对表中元素都有常熟的访问时间O(1)。

多数情况下可能找不到完美哈希函数,我们的目标是寻找一个好的哈希函数,它能合理地将元素散列到表中以尽量避免冲突。好的哈希函数仍能得到对哈希表的常数阶(O(1))访问时间。

对于一个具体的数据集,可用多种方法设计哈希函数。

1)除留余数法 哈希函数为:H(key)=key mod P,其中p 是某个正整数。这个函数的结果在0到p-1之间。一般地,p取不大于表长的最大素数。

2)折叠方法

折叠方法(folding method)中,将关键字划分为几段,然后再将它们组合或折叠再一起得到哈希地址。 首先,将关键字划分为多个子段,每个子段的长度与下标的长度一样,最后一端可能稍短。各段折叠的方式可以有多种变形。

在移位折叠方法(shift folding method)中,这些子段相加得到哈希地址。

边界折叠(boundary folding)法 也有多种变形。但一般来说,先让关键字的若干子段反转然后再相加

折叠方法的其他变形是:使用不同的算法来决定反转关键字中的那些部分。

当对字符串型关键字建立哈希函数时,也可使用折叠方法。例如将字符串划分为与所需下标等长(按字节的几个子串),然后使用异或函数将几个子串组合起来。这个方法还可以将字符串转为一个数值,这样转换后,其他的方法(例如触发方法)也能用于字符串类型。

3)平方取中方法

在平方取中方法(mid-square method)中关键字自乘,然后使用抽取方法从平方结果的中抽取相应的位得到哈希地址。

4)基数转换方法

在基数转换方法(radix transform method)中关键字转换为另一种数值基数。

5)数字分析方法

数字分析方法(digit analysis method)抽取关键字中的指定位并惊醒处理从而得到哈希地址。

6)长度依赖的方法
在长度依赖的方法(length-dependent method)中,关键字和关键字的长度以某些方式组合起来,或直接当作哈希地址使用,或再进一步使用其他方法进行处理哈希地址。

将字符串中各字符按二进制格式进行处理,则长度依赖方法也可以用于字符串类型。

2.解决冲突

如果能对具体的数据集找到一个完美哈希函数,就不必考虑冲突问题,所谓冲突是指多个元素或关键字映射到哈希表中的同一个位置。 如果找不到完美哈希函数,或找到哈希函数不实用(例如时间开销太大),则采用合理的哈希函数并增加冲突解决机制。

有多个方法可以处理冲突。

1)链式方法

处理冲突的链式方法(chaining method),将哈希表看作是集合的表而不是各独立单元的表。哈希表的每个单元中保存一个指针,指向由所有映射到该地址的关键字组成的表。
使用该方法,最坏的情况是 ,哈希函数不能很好地将元素散列到表中,所以最终得到一个含n个元素的链表,或是几个含约n/k个元素的链表,这里k是个相对较小的常量值。这种情况下,哈希表的插入和查找都变为O(n)。

2)开放地址法

开放地址法(open addressing method)处理冲突的方法是,在表中寻找不同于该元素原先哈希到的另一个开放的位置,新的地址计算公式为:

Hi=(H(key)+di)mod m i = 1,2,‘’‘’‘’,k(k≤m-1) 其中,H(key)是哈希函数,m为哈希表长,di 是增量序列。

若di=1,2,3,…,m-1,称为线性探测再散列方法(linear probing);也称为线性探查;

若di=1²,-1²,2²,-2²,3²,…,±K²(k≤m/2),称为二次探测再散列方法(quadratic probing ),也称为二次探查;

若用伪随机数序列当作增量序列di,称为伪随机数再散列法,也称为伪随机数探查。

线性探查方法的优点是再探查序列到达发生冲突的位置(基位置)之前,表中所有位置都可以作为插入新记录的候选位置,但它的一次再探查由可能导致后序记录的冲突。这种把元素怒聚集到一起的倾向称为基本聚集。

使用装填因子a描述哈希表的装满程度:

a=表中填入的记录数/哈希表的长度

1.5.7字符串模式匹配

字符串是程序中最常处理的数据类型之一,字符串也简称为串。串是由零个或多个字符串组成的有序序列,一般记为S=’a0a1…an-1‘(n≥0)

在匹配过程中,一旦遇到Tj和p不相等,则:

  • 如果i>0,那么在下一趟比较时模式串P的起始比较位置是Pnext(i),即将模式串P右移i-next[i]个位置,目标串T的指针不回溯,仍指向上一趟失配的字符;

  • 如果i=0,则目标串T指针右移动一个位置,模式串P指针回到P0,继续继续进行下一趟匹配比较;

  • 若next[i]=0,p中任何字符都不必要再与Tj比较,而应将P右移i+1个位置,从P0和tj+1开始重新进行下一次比较。

    对于模串’abaabcac’,其next函数值如表1-6所示。

    表1-6模串”abaabcac“的next值

位置 01234567
模串 abaabcac
next值 -10011201

1.5.8查找算法的分析及应用

查找算法的时间复杂度及应用可以简单概括如图1-7所示

表1-7 查找算法的时间复杂度

算法 运行时间 备注
顺序查找 O(n) 适用于数组及链表,关键字可无序
折半查找 O(log2n) 适用于数组,关键字有序
哈希查找 O(1) 计算哈希地址,查找元素(常数时间)

你可能感兴趣的:(数据结构,算法,链表)