1、第八章 查找,1、静态查找表 2、动态查找表 3、哈希查找表,查找表,查找表是由同一类型的数据元素(或记录)构成的集合。 操作: 查询某个特定的元素是否在查找表中。 检索某个特定的数据元素的各种属性。 在查找表中插入一个数据元素。 从查找表中删去某个特定元素。,查找的概念,关键字:是数据元素(或记录)中某个数据项的值,可以标识(识别)一个数据元素(或记录)。 查找:根据给定的值,在查找表中确定一个关键字等于给定值的记录或数据元素。 若表中存在这样的一个记录,则称查找是成功的; 若表中不存在关键字等于给定值的记录,则称查找不成功。,实施查找两种不同的查找环境 静态环境:被查找的数据集合经查找后并
2、不改变,不能插入、删除、修改记录。 动态环境:被查找的数据集合经查找后可以改变,可以插入、删除、修改记录。,静态查找表,查询某个“特定的”数据元素是否在查找表中; 检索某个“特定的”数据元素的各种属性。,主要操作,Search(ST,key):在静态表中查找给定关键字key,如果存在关键字为k的记录,则返回该记录的位置,否则返回0。,顺序表的查找,应用范围:顺序表或线性链表表示的静态查找表。表内元素之间无序。(即线性表) 顺序查找表的表示:typedef struct ElemType * elem;或ElemType elemlistSize/表中元素int length; /表长度 SSt
3、able;,顺序查找的实现:从表中最后一个记录开始,逐个进行记录的关键字和给定值的比较。int Search_Seq( Sstable ST, KeyType key ) ST.elem0. key = key; / 哨兵for ( i = ST.length ; ! EQ(ST.elemi. key, key ) ; - - i ) ; return i; /返回 0,查找失败;否则,找到 key 所在的数组元素的下标地址,设置哨兵的好处:在顺序表中总可以找到待查结点。否则必须将 判断条件 i = 0 加进 for 语句。,例1: 查找 key = 8 的结点所在的数组元素的下标。,0,1,
4、2,n-3,n-2,n-1,n,i,数组 ST.elem,key,8,100,10,0,7,1,3,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,7,1,3,i,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,7,1,3,i,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,7,1,3,i,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,7,1,3,i,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key
5、,8,100,10,0,7,1,3,i,查找失败,则 i = 0;,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,7,1,3,i,例2: 查找 key = 8 的结点所在的数组元素的下标。,in2,0,1,2,n-3,n-2,n-1,n,数组 ST.elem,key,8,100,10,0,8,1,3,i,性能分析,平均查找长度ASL:为确定记录在查找表中的位置,需和给定值进行比较的关键字个数的期望值。 成功查找情况下:设每个结点的查找概率相等,查找不成功的情况下:和给定值比较的关键字个数为n1 一般查找情况下(包含成功、不成功两种情况),可能性相等
6、,每个结点的查找概率也相等。因此,顺序查找的平均查找长度为:,有序表的查找,折半查找(或二分查找法)1、应用范围:顺序表,表内元素之间有序。不可直接用于线性链表。2、查找过程:确定待查记录所在范围的上界high和下界low指针,指针mid指示区间的中间位置,确定待查元素位置。mid (lowhigh)/2 比较待查元素关键字和给定关键字,若:,待查元素关键字和给定关键字相等,则返回位置指针mid, 给定关键字大于待查元素关键字,lowmid+1,,若low上界high,说明表中没有关键字等于key的元素,查找不成功。,0,1,2,mid=4 但 key=9 10, 向左,key,4,8,9,1
7、0,11,13,19,3,4,5,6,7,high=7,low=1,例:查找 key = 9 的结点所在的数组元素的下标地址。,0,1,2,mid=4,key,4,8,9,10,11,13,19,3,4,5,6,7,high=(mid-1)= 3,low=1,0,1,2,mid=2,但 key=9 8, 向右,key,4,8,9,10,11,13,19,3,4,5,6,7,high=3,low=1,0,1,2,key,4,8,9,10,11,13,19,3,4,5,6,7,high=3,low=mid+1=3,mid=2,0,1,2,key,4,8,9,10,11,13,19,3,4,5,6,
8、7,high=3,low=3,mid=3;但 key=9 中点值也为 9 ,找到,查找k5的结点所在数组元素的下标,0,1,2,mid=4 但 key=5 10, 向左,key,4,8,9,10,11,13,19,3,4,5,6,7,high=7,low=1,0,1,2,mid=4,key,4,8,9,10,11,13,19,3,4,5,6,7,high=3(mid-1),low=1,0,1,2,mid=2,key,4,8,9,10,11,13,19,3,4,5,6,7,high=3,low=1,0,1,2,mid=2; 但 key=5 8, 向左,key,4,8,9,10,11,13,19,
9、3,4,5,6,7,high=3,low=1,0,1,2,mid=2,key,4,8,9,10,11,13,19,3,4,5,6,7,high=1(mid-1),low=1,0,1,2,mid=1,key,4,8,9,10,11,13,19,3,4,5,6,7,high=1,low=1,0,1,2,mid=1; 但 key=5 4, 向右,key,4,8,9,10,11,13,19,3,4,5,6,7,high=1,low=1,0,1,2,mid=1; 但 key=5 4, 向右,key,4,8,9,10,11,13,19,3,4,5,6,7,high=1,low=2 (mid+1),失败条件
10、:low high; 处于间隙中的键值导致这种情况!,实现算法,int Search_bin ( SStable ST, KeyType key )/ 在有序表中查找关键字之值为 key 的结点,找到返回该结点 在表中的下标地址,否则返回 0 low = 1 ; high = ST.length ;while ( low = high ) mid = ( low + ligh ) / 2 ; if ( EQ(ST.elemmid. key, key ) return mid ;else if ( LT( key , ST.elemmid. key ) ) high = mid -1 ;else
11、 low = mid + 1; return 0 ;,搜索成功时检测指针停留在树中某个结点。 搜索不成功时检测指针停留在某个外结点(失败结点)。,35,15,45,50,25,10,20,30,搜索22,搜索45,有序顺序表的折半搜索的判定树 ( 10, 20, 30, 40, 50, 60 ),10,50,=,=,=,=,=,=,30,20,40,60,折半搜索性能分析,若设 n = 2h-1,则描述折半搜索的判定树是高度为 h 的满二叉树。2h = n+1, h = log2(n+1)。 第1层结点有1个, 搜索第1层结点要比较1次; 第2层结点有2个, 搜索第2层结点要比较2次; , 第
12、 i (1 i h) 层结点有 2i -1个, 搜索第 i 层结点要比较 i次,。 假定每个结点的搜索概率相等,即 pi = 1/n,则搜索成功的平均搜索长度为,练习,画出对长度为10的有序表进行折半查找的判定树,并求其等概率时查找成功的平均查找长度。,动态查找表,特点:用于频繁插入、删除或查找。 二叉排序树和平衡二叉树 1、二叉排序树(又称为二叉搜索树):空或有一个根;或者是具有下列性质的二叉树: (1)若它的左子树不空,则左子树上所有结点的值均小于根结点的值; (2)若它的右子树不空,则右子树所有结点的值均大于根结点的值。 (3)左右子树也分别为二叉排序树。,122,250,300,110
13、,200,99,L,N,P,E,M,C,Y,105,230,216,二叉排序树,分割式查找法: 若根结点的关键字值等于查找的关键字,成功 否则, 若给定值小于根结点的关键字值,查其左子树。 若给定值大于根结点的关键字值,查其右子树。在左右子树上的操作类似。,Bitree SearchBST ( BiTree T, KeyType key )/ 在二叉分类树查找关键字之值为 key 的结点,找到返回该结点的地址,否则返回空。 if ( ( !T) | EQ( key, T -data. key ) ) return ( T ) ; else if ( LT( key , T -data. key
14、 ) ) return (SearchBST ( T - lchild, key ); else return (SearchBST ( T - rchild, key ); ,二叉排序树的插入: 过程: 首先执行查找算法,找出被插结点的父亲结点。 判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。 若二叉树为空。则首先单独生成根结点。 注意:新插入的结点总是叶子结点,并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。 进行插入时,不需要移动任何结点。,例:将数的序列:122、99、250、110、300、280 作为二叉排序树的结点的关键字值,生成二叉排序树
15、。,122,例:插入值为280的结点,二叉排序树的删除 分为以下三种情况: (设被删结点为p,父结点为f,p是f的左孩子。) 若p为叶子结点,直接删除,更改其父结点的指针。,PL、PR皆 空, 直接删除,15,60,70,30,20,50,60,30,20,50,例:删除15、70结点,若p的左子树为空或右子树为空。另其子树直接成为其父结点f的左子树。,F,PL为空,删除后的情况。,PL或PR为空,,122,250,300,110,200,99,105,230,216,400,450,500,被删结点,122,250,300,200,230,216,400,450,500,110,105,删除
16、,99,PL为空,删除后的情况。,若p的左、右子树均不为空,选取“替身”代替p。 其一用p的左子树中最大的结点s(p的左子树中最右的结点)代替p,s的左子树为s的父结点的右子树。 其二另p的左子树为其父结点的左子树。P的右子树为p的左子树中最大结点s的右子树。,F,S,C,Q,QL,SL,F,C,Q,QL,S,SL,1.删除法,2.删除法,二叉排序树的查找分析 含有n个结点的二叉排序树的平均查找长度和树的形态有关。当先后插入的关键字有序时,构成的二叉排序树变为单支树。,15,60,70,30,20,50,15,60,70,30,20,50,ASL=(1+2+2+3+3+3)/6=14/6,AS
17、L=(1+2+3+4+5+6)/6=21/6,等概率的情况下,在最坏情况下,如前页右图,树的深度为n,其平均查找长度为 .最好情况,平均查找长度和lnn等数量级。为了提高查找速度,一般使用丰满树,但构造困难,所以使用平衡二叉树。,对于给定结点的关键字集合 5 , 7 , 3 , l , 9 , 6 , 4 , 8 , 2 , 10 试构造一棵二叉排序树; 求等概率情况下的平均查找长度 ASL,已知如下长度为12的表, (Jan,Feb,Mar,Apr,May,June,July,Aug,Sep,Oct,Nov,Dec) 按表中元素的顺序依次插入一棵初始为空的二叉排序树,画出插完后的二叉排序树,
18、并求其在等概率的情况下查找成功的平均查找长度。,平衡二叉树(Balanced Binary Tree) (AVL树),平衡二叉树或者是一棵空树,或者是具有下列性质的二叉树: (1)它的左子树和右子树都是平衡二叉树 (2)且左子树和右子树的深度之差的绝对值不超过1 平衡因子:结点的平衡度是该结点的左子树深度减去右子树的深度。 平衡二叉树:每个结点的平衡因子都为1、1、0 的二叉树。 注意:丰满树必为平衡树,平衡树不一定是丰满树。 AVL树的深度和logN是等数量级的,因此,平均查找长度也和logN是同数量级。,平衡二叉树的插入,假设由于在二叉排序上插入结点而失去平衡的最小子树根结点指针为a,则失
19、去平衡后需要调整的规律如下:1、LL情况(表示新插入的结点在a的左子树的左子树上),A,B,+1,h-1,0,+2,+1,h,h-1,h-1,LL 改组,BL,BR,AR,B,A,0,h,0,h-1,h-1,BL,BR,AR,a,进行一次向右的顺时针旋转,被插结点,8,7,6,例:新插入结点为6,8,7,6,2、RR情况(插入结点在a的右子树的右子树上),A,h-1,-1,-2,RR 改组,AL,a,进行一次向左的逆时针旋转,B,BL,BR,h,-1,h-1,AL,0,A,h-1,0,AL,B,BL,BR,AL,h,0,8,9,10,例:新插入结点为10,10,9,8,3、LR情况:新插入的结
20、点在a的左子树的右子树上。 情况A:,A,B,+1,h-1,0,+2,-1,h-1,LR 改组,BL,AR,a,C,CL,CR,h-2,h-2,h-1,0,+1,先左旋,再右旋,14,13,9,例:新插入结点为11,10,12,11,A,h-1,h-1,AR,C,CR,h-2,h-1,B,CL,A,B,+1,h-1,0,+2,-1,h-1,LR 改组,BL,AR,a,C,CR,CL,h-1,h-2,h-2,0,-1,C,B,0,h-1,BL,AR,A,CL,h-1,CR,h-2,+1,0,h-1,情况B:,4、RL情况:插入结点在a的右子树的左子树上。,A,B,-1,0,+2,1,h-1,BR
21、,AL,a,C,CL,CR,h-2,h-2,0,h-1,0,+1,h-1,C,A,AL,BR,B,h-2,CR,h-1,0,-1,h-1,h-1,0,先右旋,再左旋,12,9,11,例:新插入结点为10,8,10,13,作业,已知长度为12的表为5,4,8,1,9,7,6,2,12,11,10,3。 按表中元素的次序建立一个二叉排序树,并求在等概率的情况下查找成功的平均查找长度。 按表中元素顺序构造一棵AVL树,并求其在等概率情况下查找成功的平均查找长度。,哈希表,什么是哈希表设M存储区是一个有限的连续的地址集,为0 m1。设表具有n个结点a1,a2, a3an、这些结点相应的关键字值分别为k
22、1, k2, k3, kn。又设 f 函数是一个确定的函数,它能将关键字 值 ki 映射为 M 存区的地址:即,f( ki ) - 0m-1 (注意:是一个确定的地址) 该地址就是结点 ai 的存放地址或称为哈希地址。f函数通常称之为 hashing 函数,而 M 存区称之为 hashing 表。,哈希函数是一个映象,因此设定很灵活,使得任何关键字由此所得的哈希函数都落在表长允许范围之内即可。 对不同的关键字可能得到同一哈希地址,即key1key2,而f(key1)f(key2),这种现象称为冲突。 具有相同函数值的关键字对该哈希函数来说称为同义词。,哈希函数的构造方法,1、直接定址法H(ke
23、y) = key 或 H(key) = a key b 如:k1, k2 分别有值 10 、1000;选10 、1000 作为存放地址。简单、不经济。 2、除留余数法取关键字被某个不大于哈希表表长m的数p除后所得的余数作为哈希地址。即:H(key) = key MOD p 或 H(key) = key MOD p + c 这里 p m一般情况下,可以选p为质数,3、数字分析法 4、平方取中法取关键字平方后的中间几位为哈希地址。 例: (4731)2 223 82 361 ;选取 82 (在 m 100 情况下)。 5、折叠法 将关键字分成位数相同的几部分,然后取这几部分的叠加和作为哈希地址。移
24、位叠加:将分割后的每一部分的最低位对齐,然后相加。 间界叠加:从一端向另一端沿分割界来回折送,然后对齐相加。,381 412 975 1768,975 214 381 1570,例:key = 381,412,975 选取 768 或 570 作为散列地 址(在 m 1000 情况下)。,6、随机数法选择一个随机数,取关键字的随机函数值为它的哈希地址,即H(key)=random(key),random为随机函数。,处理冲突的方法,冲突是指由关键字得到的哈希地址为j的位置上已有记录。处理哈希地址的冲突时,直到得到的哈希地址Hk不发生冲突为止。,1、开放地址法Hi=( H(key)+ di )
25、MOD m i=1,2, k(km-1) 其中H(key)为哈希函数; m为哈希表长; di为增量序列,可以有三种取法 (1) di 1,2, 3, m1称为线性探测再散列; (2) di=12,-12,22,-22, k2(k m 2),称为二次探测再散列。 (3) di伪随机数序列,称伪随机探测再散列。,例:长度为11的哈希表中已有关键字17,60,29的记录,哈希函数H(key)=key MOD 11,用线性探测在散列处理冲突,关键字为38的记录的哈希地址为:?H(38)=38 MOD 11=5,与60冲突H(38)=(5+1)MOD 11=6,与17冲突H(38)=(5+2)MOD 1
26、1=7,与29冲突H(38)=(5+3)MOD 11=8 不发生冲突,2、链地址法:将所有关键字为同义词的记录存储在同一线性链表中。凡是哈希地址为i的记录都插入到头指针为Hashi的链表中。,0,1,5,例题:已知一组关键字为(19,14,23,01,68,20,84,27,55,11,10,79)按哈希函数H(key) mod 13和链地址法处理冲突构造所得的哈希表如图:,该例按照线性探测再散列处理冲突,则哈希表为: (19,14,23,01,68,20,84,27,55,11,10,79) 哈希函数H(key) mod 13,3、公共溢出区法:将发生冲突的结点都存放在一个公共溢出区内。通常
27、用于组织存在于外存设备上的数据文件。M 存区只存放一个记录。发生冲突的记录都存放在公共溢出区内。,哈希查找性能分析,哈希表的查找过程是给定值和关键字进行比较的过程,以平均查找长度衡量查找效率。 查找过程中需要和给定值进行比较的关键字个数取决于:哈希函数、处理冲突的方法、哈希表的装填因子,查找成功的平均查找长度为: ASL=P*各记录插入的次数之和 查找不成功的时候的平均查找长度为:,如前例按照链地址法的ASL为 1/12(1*6+2*4+3+4)=1.75 按照线性探测再散列的ASL为 1/12(1*6+2+3*3+4+9)=2.5,哈希表的装填因子定义为:哈希表的平均查找长度是的函数,而不是
28、表长n的函数,因此ASL不依赖于n,设哈希表为HT13, 待插入的关键码序列为 12, 23, 45, 57, 20, 03, 78, 31, 15, 36,散列函数为 H (key) = key %13。现采用线性探测再散列法解决冲突,试画出相应的哈希表, 并计算等概率下搜索成功的平均搜索长度,使用散列函数 H(key) = key % 13,有H(12) = 12, H(23) = 10, H(45) = 6,H(57) = 5, H(20) = 7, H(03) = 3,H(78) = 0, H(31) = 5, H(15) = 2,H(36) = 10.(1) 利用线性探查法造表:ASLsucc = (1+1+1+1+1+1+4+1+2+1) =14/10,0 1 2 3 4 5 6 7 8 9 10 11 12,练习,选取哈希函数H(k)=(3k)%11,用线性探测再散列法处理冲突。试在010的散列地址空间中,对关键字序列(22,41,53,46,30,13,01,67)构造哈希表,并求等概率情况下查找成功与不成功时的平均查找长度。,