1 / 57

第八章 查找

第八章 查找. 查找运算是计算机中最常用的操作之一,计算机大约有 40% 的运算与查找有关。 概念和术语 8.1 静态查找表 8.2 动态查找表 8.3 哈希表. 相关概念和术语. 数据项. 查找表 同一类型的记录 ( 数据元素 ) 的 集合 。 查找 指定某个值,在查找表中确定是否存在一个记录,该记录的 关键字 等于给定值。 关键字 记录 ( 数据元素 ) 中的某个数据项的值。 主关键字 该关键字可以唯一地标识一个记录。 次关键字 该关键字不能唯一标识一个记录。. 数据元素.

adia
Download Presentation

第八章 查找

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第八章 查找 查找运算是计算机中最常用的操作之一,计算机大约有40%的运算与查找有关。 概念和术语 8.1 静态查找表 8.2 动态查找表 8.3 哈希表

  2. 相关概念和术语 数据项 查找表 同一类型的记录(数据元素)的集合。 查找 指定某个值,在查找表中确定是否存在一个记录,该记录的关键字等于给定值。 关键字 记录(数据元素)中的某个数据项的值。 主关键字 该关键字可以唯一地标识一个记录。 次关键字 该关键字不能唯一标识一个记录。 数据元素

  3. 静态查找表 对查找表的查找仅是以查询为目的,不改动查找表中的数据。 动态查找表 在查找的过程中同时插入不存在的记录,或删除某个已存在的记录。 查找成功 查找表中存在满足查找条件的记录。 查找不成功 查找表中不存在满足查找条件的记录。

  4. 内查找 整个查找过程都在内存中进行。 外查找 在查找过程中需要访问外存。 平均查找长度ASL——查找方法时效的度量 为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值。 查找成功时的ASL计算方法: n:记录的个数 pi:查找第i个记录的概率,且 ( 不特别声明时认为等概率 pi =1/n ) ci:找到第i个记录所需的比较次数

  5. 8.1 静态查找表 8.1.1 顺序表的查找 8.1.2 有序表的查找 8.1.3 静态树表的查找 8.1.4 索引顺序表的查找

  6. 8.1.1 顺序表的查找 以顺序表或线性链表表示静态查找表,则Search函数可用顺序查找来实现.本节只讨论它在顺序存储结构中的实现. typedef struct {    KeyType key;           …… } ElemType; //数据元素定义 typedef struct {          ElemType *elem; //0号单元留空 int length; } SSTable;

  7. 顺序查找:用所给关键字与线性表中各元素的关键字逐个比较,直到成功或失败。顺序查找:用所给关键字与线性表中各元素的关键字逐个比较,直到成功或失败。 int Search_Seq(SSTable ST,KeyType key){ //在顺序表ST中顺序查找其关键字等于key的元素. //若找到,函数值为该元素在表中的位置 //否则为0 ST.elem[0].key=key; for(i=ST.length;ST.elem[i].key!=key;i--); return i ; } 其中ST.elem[0] 称为监视哨,可以起到防止越界的作用。

  8. [性能分析] • 空间:一个辅助空间。 • 时间: 查找成功时的平均查找长度 设表中各记录查找概率相等 ASLs(n)= =(1+2+ ... +n)/n =(n+1)/2 [算法特点] • 算法简单,对表结构无任何要求 • n很大时查找效率较低 • 改进措施:非等概率查找时,可将查找概率高的记录尽量排在表后部。

  9. 8.1.2 有序表的查找 以有序表表示静态查找表时,Search函数可用折半查找来实现。 折半查找法又称为二分法查找法, 其基本过程是:将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

  10. low mid hign hign mid hign low mid mid 图8.1 用折半查找法查找12、50的过程 其中mid=(low+high)/2,当high<low时,表示不存在这样的子表空间,查找失败。 成功! (a) 用折半查找法查找12的过程

  11. low mid hign low mid mid low high 图8.1 用折半查找法查找12、50的过程 其中mid=(low+high)/2,当high<low时,表示不存在这样的子表空间,查找失败。 失败! (b) 用折半查找法查找50的过程

  12. 折半查找的算法 int Search_Bin(SSTable ST,  KeyType key) /*在有序表ST中折半查找其关键字等于key的元素,若找到,则函数值为该元素在表中的位置,否则为0*/ {       low=1 ;   high=ST.length; /*置区间初值*/        while  ( low<=high)         {mid=(low+high) / 2;          if  (key==ST.elem[mid]. key)  return mid ;/*找到待查元素*/         else  if (key<ST.elem[mid]. key)  high=mid-1; /*未找到,则继续在前半区间进行查找*/         else  low=mid+1;/*继续在后半区间进行查找*/           }       return 0; }

  13. -1 3-4 6-7 9-10 1-2 2-3 4-5 5-6 7-8 8-9 10-11 11- [性能分析] 判定树(描述查找过程的二叉树) 1 6 < = > 2 3 9 h=log2n+1 {同完全二叉树,二叉树性质4} 成功查找时的平均查找长度: ASLs= 例:ASLS=(1*1+2*2+3*4+4*4)/11=3 不成功查找时的比较次数:最多h次 1 4 7 10 内结点 外结点 2 5 h 8 11 (n>50)

  14. 折半查找方法的优缺点 折半查找方法的优点是比较次数少,查找速度快,平均性能好; 其缺点是要求待查表为顺序存储的有序表,插入删除困难。 因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

  15. 42 4 36 3 19 2 67 5 15 1 42 4 15 1 36 3 19 2 8.1.3 静态树表的查找 [问题出发点] 讨论有序表中各记录查找概率不等时,查找成功时的ASL。 关键字 15 19 36 42 67 查找概率0.1 0.2 0.1 0.4 0.2 折半查找 高概率为根 +折半 ASL= =2.3 ASL= =1.8 67 5

  16. [静态最优查找树] 定义:查找性能最佳的判定树。 性质:带权内路径长度之和PH为最小值。 PH= 与ASL成正比 其中n:二叉树上结点的个数(有序表长度) hi:第i个结点在二叉树上的层次数 wi=cpi:c为某个常量; pi:第i个结点的查找概率

  17. 最优查找体现的原则: 1)最先访问的结点应是访问概率最大的结点; 2)每次访问应使结点两边尚未访问的结点的被访概率之和尽可能相等。

  18. [次优查找树的构造方法] PH值近似为最小 比静态最优查找树易于构造,时间开销少 已知按关键字有(升)序的记录序列: ( rl, rl+1, ..., ri-1, ri, ri+1, ..., rh-1, rh ) 1)选取记录ri作为根结点: 计算所有pi (lih) 找出最小pi的对应的i; 若相邻关键字的权值大,则确定为权值大的关 键字对应的i

  19. 简化计算pi的方法: 设定累计权值和 swi = 则pi = |(swh-swi)-(swi-1-swl-1)| =|(swh + swl-1)- swi - swi-1| 设 sw0=0 2)ri的左子树: ( rl, rl+1, ..., ri-1)构造的次优查找树 3)ri的右子树: ( ri+1, ..., rh-1, rh )构造的次优查找树 [例]教材228页 例8-1

  20. [次优查找树上的查找步骤] 设给定的查找值为K 将根结点作为当前考察的结点 1)若当前结点指针为nil,则返回空指针 2)将当前结点的关键字key与K比较, 若K=key,则返回当前结点的指针; 若K>key,将其右孩子作为当前结点,转1); 若K<key,将其左孩子作为当前结点,转1); [查找性能] 比较次数不超过树的深度,O(log2n)

  21. 8.1.4索引顺序表的查找 若以索引顺序表表示静态查找表,则Search函数可用分块查找来实现。 分块查找法要求将列表组织成以下索引顺序结构: 首先将列表分成若干个块(子表)。一般情况下,块的长度均匀,最后一块可以不满。每块中元素任意排列,即块内无序,但块与块之间有序。 构造一个索引表。其中每个索引项对应一个块并记录每块的起始位置,和每块中的最大关键字(或最小关键字)。索引表按关键字有序排列。

  22. 图8.2 分块查找法示意图

  23. 分块查找的基本过程: ⑴ 首先,将待查关键字K与索引表中的关键字进行比较,以确定待查记录所在的块。具体的可用顺序查找法或折半查找法进行。 ⑵ 进一步用顺序查找法,在相应块内查找关键字为K的元素。 例如,在上述索引顺序表中查找38。首先,将38与索引表中的关键字进行比较,因为22<38≤48,所以36在第二个块中,进一步在第二个块中顺序查找,最后在10号单元中找到38。

  24. 分块查找的平均查找长度 由两部分构成,即查找索引表时的平均查找长度为LB,以及在相应块内进行顺序查找的平均查找长度LW。 ASLbs=LB+LW 假定将长度为n的表分成b块,且每块含s个元素,则b=n/s。又假定表中每个元素的查找概率相等,则每个索引项的查找概率为1/b,块中每个元素的查找概率为1/s。若用顺序查找法确定待查元素所在的块,则有:

  25. 8.2 动态查找表 动态查找表的特点是: 表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键字等于key的记录,则查找成功返回,否则插入关键字等于key的记录 8.2.1 二叉排序树 8.2.2 平衡二叉树

  26. 45 24 53 13 28 90 8.2.1 二叉排序树BST(二叉查找/搜索树) 1. 定义 二叉排序树或者是空树,或者是满足如下性质的二叉树: 1)若其左子树非空,则左子树上所有结点的值均小于根结点的值; 2)若其右子树非空,则右子树上所有结点的值均大于等于根结点的值; 3)其左右子树本身又各是一棵二叉排序树 2. 性质 中序遍历一棵二叉排序树,将得到一个 以关键字递增排列的有序序列

  27. 图8.3 二叉排序树 (a)二叉排序树示例1 若中序遍历,则可得到一个递增有序序列为:1,2,3,4,5,6,7,8,9。

  28. 图8.3 二叉排序树 (b)二叉排序树示例2(根据字符ASCII码的大小)

  29. 二叉排序树的结点结构说明 在下面讨论二叉排序树的操作中,使用二叉链表作为存储结构,其结点结构说明如下: typedef struct node { KeyType key ; /*关键字的值*/ struct node *lchild,*rchild;/*左右指针*/ }BSTNode,*BSTree;

  30. T T 45 45 f 24 53 24 53 f 12 28 90 12 28 90 32 3. 在二叉排序树上的操作 1)查找 [例]Key=28 Key=32 [算法描述] 2) 插入 [算法描述] 3) 生成

  31. 查找算法 返回 BiTree SearchBST(BiTree T,KeyType key){ //在根指针T所指二叉树中递归地查找某关键字等于 //key的数据元素,若查找成功,则返回指向该数据元 //素结点的指针,否则返回空指针 if ((!T)||(T->data.key) return(T); else if (key< T->data.key) return(SearchBST(T->lchild,key)); else return(SearchBST(T->rchild,key)); }

  32. 插入算法(1)—查找算法改写 Status SearchBST(BiTree T,KeyType key,BiTree f, BiTree &p){ /*在根指针T所指二叉树中递归地查找某关键字等于key 的数据元素,若查找成功,则p指向该数据元素结点,并返回TRUE,否则p指向查找路径上的最后一个结点,并返回FALSE,f指向T的双亲,其初始值为NULL*/ if (!T) {p=f;return FALSE; } else if (key= T->data.key) {p=T;return TRUE}; else if (key< T->data.key) return SearchBST(T->lchild,key,T,p); else return SearchBST(T->rchild,key,T,p); }

  33. 返回 插入算法(2) Status InsertBST(BiTree &T,ElemType e){ /*当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE,否则返回*/ if (!SearchBST(T,e.key,NULL,p){ s=(BiTree)malloc(sizeof(BiTNode)); s->data=e;s->lchild=s->rchild=NULL; if (!p) T=s}; else if (e.key< p->data.key) p->lchild=s; else p->rchild=s; return TRUE;} else return FALSE; }

  34. 45 24 53 12 28 90 3) 生成 [算法步骤] 反复执行以下操作 a. 读入一个记录,设其关键字为key; b. 调用SearchBST(),确定插入位置; c. 调用InsertBST(),实施插入结点的操作;[例]{45,24,53,45,12,24,90,28}

  35. 设*p是被删除结点,则分以下几种情况: (1)*p是叶子结点:修改其双亲指针即可 (2)*p只有左孩子:用*p的左子树代替以*p为根的子树 *p只有右孩子:用*p的右子树代替以*p为根的子树 (3)*p有两个孩子:找到*p的中序后继(或前趋)结点*q,*q的数据复制给*p,删除只有右孩子(或左孩子)/无孩子的*q 53 (3) 20 90 (2) (2) 10 50 86 95 41 52 88 91 4 12 87 30 45 89 92 39 (1) 4) 删 除

  36. 对同样一些元素值,如果输入顺序不同,所创建的二叉树形态也不同。如上面的例子如果输入顺序为 24,53,90,12,28,45,则生成的二叉排序树如下图所示: 4. 性能分析

  37. 被删除结点的不同情况分析: • 给定树的形态,等概率查找成功时的ASL=ci /n • 最差(单支树):(n+1)/2 • 最好(类似折半查找的判定树):log2(n+1)-1 • 随机:1+4log2n • 关键字有序出现时,构造出“退化”的二叉排序树,树深为n,各种操作代价O(n)。避免方法:采用平衡二叉树

  38. 1 -1 -1 0 1 0 0 8.2.2 平衡二叉树(AVL树) 1. 定义 平衡二叉树或者是空树,或者是满足如下性质的二叉排序树: 1)它的左、右子树的高度之差的绝对值不超过1; 2)其左右子树本身又各是一棵平衡二叉树。 二叉树上结点的平衡因子: 该结点的左子树高度减去右子树的高度。 平衡二叉树 非平衡二叉树

  39. otherinfo lchild bf key rchild 2. 定理 一个具有n个结点的平衡二叉树形,其高度h为 log2(n+1)  h  1.4404log2(n+2)-0.328 结论:最坏情况下,AVL树的高度约为1.44log2n,而完全平衡的二叉树高度约为log2n,因此AVL树是接近最优的,其平均查找长度与log2n同数量级。 3. 结点的存储结构 lchild:左孩子指针 rchild:右孩子指针 bf:平衡因子 key:记录的关键字 otherinfo:记录的其它数据成分

  40. 4. 在平衡二叉树上的操作 1)查找 查找方法同二叉排序树。 2)插入 [例] 平衡二叉树的生成过程{13,24,37,90,53} 13 24 37 90 53

  41. a 2 0 A B A 1 B 0 1 B A 0 AR AR BL BR AR BL BR BL BR 插入的结点 [调整范围的确定] 插入结点后,找到离插入结点最近且平衡因子绝对值超过1的祖先结点,则以该结点为根的子树将是可能不平衡的最小子树,可将重新平衡的范围局限于这棵子树。 [调整的规律] 设失去平衡的最小子树的根结点指针为a • LL型平衡旋转——一次顺时针旋转

  42. -1 -1 0 A B a A B 0 B -1 A 0 AL AL BR AL BL BL BR BL BR a 1 2 C A A 0 B 0 B -1 B A -1 0(1) C C 0 1(-1) AR AR CL CR AR BL BL BL CL CR CL CR • RR型平衡旋转——一次逆时针旋转 • LR型平衡旋转——一次逆时针旋转+一次顺时针旋转

  43. 0 A -1 A -2 C B 0 B A 0(1) B -1(0) 0 C C 1(-1) AL AL CL CR BR BR BR AL CL CR CL CR • RL型平衡旋转——一次顺时针旋转+一次逆时针旋转 [算法描述]教材236 3)删除 (思路同插入) • 将删除结点q转化为q最多有一个孩子的情形,即若q有两个孩子,则以其中序前驱/后继结点r取代它,删除r; • 若树的平衡性被破坏,利用单一/双重旋转恢复。

  44. 8.3 哈希表 8.3.1 概述 8.3.2 哈希函数的基本构造方法 8.3.3 处理冲突的常用方法 8.3.4 哈希表的查找及其分析

  45. 8.3.1 概述 [哈希表的基本思想] 在记录的存储地址和它的关键字之间建立一个确定的对应关系;这样,理想状态不经过比较,一次存取就能得到所查元素。 [术语] 哈希表 一个有限的连续的地址空间,用以容纳按哈希地址存储的记录。 哈希函数 记录的存储位置与它的关键字之间存在的一种对应关系。 Loc(ri)=H(keyi) 冲突 对于keyikeyj,i j,出现的H(keyi) = H(keyj)的现象。keyi,keyj为同义词

  46. 同义词 在同一地址出现冲突的各关键字。 哈希(散列)地址 根据设定的哈希函数H(key)和处理冲突的方法确定的记录的存储位置。 装填因子 表中填入的记录数n和哈希表表长 m之比。 = n/m (m>n,通常的取值[0.65..0.9]) [设计哈希表的过程] 1)明确哈希表的地址空间范围。即确定哈希函数的值域。 2)选择合理的哈希函数。该函数要保证所有可能的记录的哈希地址均在指定的值域内,并使冲突的可能性尽量小。 3)设定处理冲突的方法。

  47. 8.3.2 哈希函数的基本构造方法 构造原则:方法简单,运算量小;均匀分布,减少冲突。 [直接定址法] H(key)=a *key + b a、b为常数 特点:计算简单,冲突最少。 [数字分析法] 取关键字的若干数位作为哈希地址。 [平方取中法] 取关键字平方后的中间几位作为哈希地址。

  48. [折叠法] 将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几个部分的叠加和(舍去进位)作为哈希地址。 [除留余数法](最简单,最常用) H(key) = key MOD p (p≤m) m: 哈希表的表长; p: 最好为素数 [随机数法] H(key) = random(key) 特点:较适于关键字长度不等时的情况。

  49. 在实际应用中,设计哈希函数考虑的因素: • 计算哈希函数所需的时间 • 关键字的长度 • 哈希表的大小 • 关键字的分布情况 • 记录的查找频率

  50. 8.3.3 处理冲突的常用方法 1. 开放定址法 (空缺编址法) Hi = ( H(key)+di ) MOD m i=1,2, ..., k (k≤m-1) m:哈希表的表长; di:增量序列 1)线性探测再散列di= 1,2, ..., m-1 缺陷:有聚集(堆积)现象—非同义词地址冲突。 2)二次探测再散列 di= 12, -12, 22, -22, 32,...,k2 k  m/2 缺陷:不易探查到整个散列空间。 3)伪随机探测再散列di = 伪随机数序列

More Related