1、第九章 查找,概述,查找表数据结构,同各种线性或非线性的数据结构一样,查找表也是一种在实际应用中大量使用的数据结构。,查找表(Search Table)是由同一类型的数据元素构成的集合,集合中的数据元素之间存在着完全松散的关系。因此查找表是一种非常灵活的数据结构。,静态查找表和动态查找表,对查找表的常见操作: (1)查询某个“特定的”数据元素是否在查找表中; (2)检索某个“特定的”数据元素的各种属性; (3)在查找表中插入一个数据元素; (4)从查找表中删除某个数据元素。,静态查找表(Static Search Table),只对查找表作前两种“查找”操作; 动态查找表(Dynamic Se
2、arch Table),若在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已存在的某个数据元素,则此类查找表即为动态查找表。,查找,关键字,数据元素中某个数据项的值,用它可以标识一个数据元素。若它可以唯一标识一个数据元素,则称此关键字为主关键字(Primary Key)(对不同的记录,其主关键字均不同)。反之,用以识别若干数据元素的关键字为次关键字(Secondary Key)。,查找(Searching),根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。若表中存在这样的一个记录,则查找成功,查找的结果为给出整个记录的信息,或指示该记录的查找表中的位置;若表中
3、不存在关键字等于给定值的记录,则称查找不成功,查找结果可以给出一个“空”记录或“空”指针。,例子,查找表关键字(主/次)查找成功/查找失败,例子,电话号码簿中查阅电话 字典中查阅某个词 编译程序中符号表 信息处理系统中的信息表,如何进行查找,在一个结构中查找某个数据元素的过程,依赖于数据元素在结构中的地位,即依赖于数据元素的组织关系(人为的)。,在计算机中进行查找的方法随数据结构不同而不同。 即随查找表的不同而不同。,9.1 静态查找表,查找表的结构 查找过程描述 查找性能分析 查找方法比较,顺序表的查找 有序表的查找 静态树表的查找,静态查找表的抽象数据类型,P216,9.1.1 顺序表的查
4、找,查找表,用一般的顺序表或者线性链表来表示静态查找表。,顺序查找(Sequential Search),从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较,若某个记录的关键字和给定值比较相等,则查找成功,返回该记录在查找表中的位序;反之,若直至第一个记录,其关键字和给定值比较都不相等,则表中无此记录,查找失败,返回0。,int Search_Seq(SSTable ST,KeyType key ) ST.elem0.key = key; /监视哨 for( i = ST.length; ! EQ( ST.elemi.key, key ) ; -i); return i ; /找不到时
5、,i为0 ,查找性能分析,以其关键字和给定值进行过比较的记录个数的平均值作为衡量查找算法好坏的依据。,定义:为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值称为查找算法在查找成功时的平均查找长度(Average Search Lengthe)。,查找成功时的平均查找长度ASL,对于含有n个记录的查找表,查找成功时的平均查找长度为,Pi 为查找表中第i个记录被查找的概率,,Ci 为找到表中其关键字与给定值相等的第 i 个记录时,和给定值已经进行过比较的关键字个数。Ci 随查找过程不同而不同。在顺序查找的过程中,Ci取决于所查记录在表中的位置,有Ci = n i +1。,顺序查找
6、的平均查找长度,在等概率的情况下:,在概率不等的情况下:P218,查找不成功时的ASL,当查找不成功的情形不能忽视时,查找算法的平均查找长度应该是查找成功时的平均查找长度与查找不成功时的平均查找长度之和。,对于顺序查找表而言,若假设查找成功与查找不成功的可能性相同,则每个记录的查找概率相等Pi=1/2n,则有:,顺序表的优缺点:,缺点:平均查找长度较大,特别是当n很大时,查找效率较低。 优点:算法简单,适用面广。它对表结构无任何要求,无论记录是否按关键字有序均可。并且以上讨论对于线性链表同样适用。,9.1.2 有序表的查找,查找表,当静态查找表是有序表(顺序表),折半查找(Binary Sea
7、rch),例如,已知有如下11个数据元素的有序表(关键字即为数据元素的值): ( 05, 13, 19, 21, 37, 56, 64, 75, 80, 88, 92)。现在要求查找关键字为21和85的数据元素。,例子,给定值key = 21的查找过程: 给定值key = 85的查找过程:,下界low上界high,查找不成功。,int Search_Bin( SSTable ST,KeyType key ) low = 1; high = ST.length; while( low = high ) mid = ( low + high ) /2; if EQ( key , ST.elemmi
8、d.key ) return mid; else if LT( key , ST.elemmid.key ) high = mid-1; else low = mid +1; return 0; ,折半查找性能分析,折半查找的判定树树中每个结点表示表中的一个记录,结点中的值为该记录在表中的位置。这样一棵二叉树可以用来描述折半查找过程。,折半查找性能分析,折半查找查找成功的过程就是走了一条从根结点到与该记录相应的结点的路径,与给定值进行比较的关键字个数恰为该结点在判定树上的层次数。 折半查找查找失败的过程,就是走了一条从根结点到外部结点的路径,和给定值进行比较的关键字个数等于该路径上内部结点个数
9、。 因此,折半查找法在查找成功时进行比较的关键字个数最多不超过树的深度 ,在查找不成功时和给定值进行比较的关键字个数最多也不超过,折半查找的ASL,假设有序表的长度为n=2h-1,则描述折半查找的判定树是深度为h的满二叉树。 该树中层次为1的结点有1个,层次为2的结点有2个,层次为h的结点有2h-1个。 假设有序表中每个记录的查找概率相等(Pi = 1/n)。,折半查找的优缺点,优点:效率比顺序查找高; 缺点:只适用于有序表,且限于顺序存储结构,对线性链表无法进行折半查找。,9.1.3 静态树表的查找,当有序表中各记录的查找概率不相等时,单纯的折半查找的效率并不是最高的 构造一个静态最优查找树
10、,这样的二叉树的查找性能才是最佳的,9.1.4 索引顺序表的查找,查找表,以索引顺序表表示静态查找表,则Search函数用分块查找来实现。因此,分块查找又称索引顺序查找,是顺序查找的一种改进。,索引表,最大关键字,起始地址,索引表按关键字有序,则表或者有序,或者分块有序。,分块查找(索引顺序表查找),分块查找的步骤分为两步:先确定待查记录所在的块(子表);然后在块中顺序查找。 例子,在上述索引顺序表中查找38和39。,注意:由于索引项组成的索引表按关键字有序,则确定块的查找可以用顺序查找,也可以用折半查找;而块中的记录排列是任意的,则在块中只能是顺序查找。,分块查找的平均查找长度,分块查找的平
11、均查找长度为 ASLbs = Lb +Lw其中:Lb为查找索引表确定所在块的平均查找长度,Lw为在块中查找元素的平均查找长度。,分块查找的平均查找长度,若采用顺序查找块,则分块查找的平均查找长度为:,其中, n为表长,均匀分为b块,每块含有s个记录,即b =,若采用折半查找块,则分块查找的平均查找长度为:,顺序查找块的平均查找长度不仅和表长n有关,而且和每一块中的记录个数s有关。可见为了提高查找效率,在n确定的情况下,应该选择合适的s。容易证明,当s取 时,ASLbs取最小值,9.2 动态查找表,动态查找表的ADT,动态查找表的特点是,表结构本身是在查找过程中动态生成的。即,对于给定值key,
12、若表中存在其关键字等于key的记录,则查找成功返回;否则,插入关键字等于key的记录。,P226:SearchDSTable(DT,key ); InsertDSTable(&DT,e ); DeleteDSTable(&DT, e );,9.2.1 二叉排序树,查找表二叉排序树,二叉排序树(Binary Sort Tree)或者是一棵空树;或者是具有下列性质的二叉树: (1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也分别为二叉排序树。,二叉排序树的查找过程,当二叉排序树不空时,首先将
13、给定值和根结点的关键字比较,若相等,则查找成功;否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。,在下列二叉排序中查找关键字等于100的记录 在下列二叉排序中查找关键字等于40的记录,?,二叉排序树的插入,二叉排序树是一种动态查找表,其特点在于表结构本身是在查找过程中动态生成的。当树中不存在关键字等于给定值的结点时再进行插入。 新插入的结点一定是一个新添加的叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。,算法9.5(b): 在根指针为T所指的二叉排序树中递归的查找某个关键字等于key的数据元素。若查找成功,则指针 p 指向该数
14、据元素结点,并返回 TRUE;否则,指针 p 指向查找路径上访问的最后一个结点,并返回 FALSE。,算法9.6: 当二叉树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE,否则返回FALSE。,待查找的关键字序列为45, 24, 53, 45, 12, 24, 90 ,45,注意:,中序遍历二叉排序树可以得到一个关键字的有序序列。 一个无序的序列可以通过构造一棵二叉排序树而变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。,二叉排序树的删除,删除二叉排序树中结点的意义:在二叉排序树中删除一个结点,相当于删除有序序列中的一个记录。,如何在删除某个结点之后,依旧保持二叉
15、排序树的特性?,分析:三种情况,情况1:若 p 所指向的结点为叶子结点,即PL 和 PR 均为空树。此时删除指针p所指向的结点不会破坏二叉排序树的结构。只需将指针f的左子树置为NULL。,情况2:若 p 所指向的结点只有左子树 PL 或只有右子树 PR ,此时只要令 PL 或 PR 直接成为其双亲结点*f的左子树即可。,情况3:*p左右子树都不空 方法1,F,P,Pr,C,Cr,S,F,Pr,C,Cl,Cr,S,方法2,F,P,Pr,C,Cl,Cr,S,Sl,Q,F,S,Pr,C,Cl,Cr,Sl,Q,算法9.7算法9.8,二叉排序树的查找分析,二叉排序树上查找其关键字等于给定值的结点的过程,恰是走了一条从根结点到该结点的路径的过程,和给定值比较的关键字个数等于路径长度加1,因此,与给定值比较的关键字个数不超过树的深度。 二叉排序树不是唯一的,含有n个结点的二叉排序树的平均查找长度和树的形态有关。 平均性能分析P232,