1、第八章 查找,8.1 静态查找表8.1.1 顺序表的查找8.1.2 有序表的查找 8.2 动态查找表8.2.1 二叉排序树 8.3 哈希表8.3.1 什么是哈希表8.3.2 哈希函数的构造方法8.3.3 处理冲突的方法8.3.4 哈希表的查找及其分析,基本概念 查找表:由同一类型的数据元素构成的集合。对查找表的常 用操作:查询元素是否存在、查询元素属性、插入一个数据元素、删除一个数据元素 查找:也叫检索,是根据给定的某个值,在表中确定一个关 键字等于给定值的数据元素。 关键字:可以标识一个数据元素的某个数据项。 主关键字:可以唯一地识别一个数据元素的关键字。 静态查找表:只进行查询某元素在表中
2、与否或检索某元素的各种属性操作的表。 动态查找表:查找时同时进行插入表中无的元素或删除表中有的某元素的表。,8.1.1 顺序表的查找 查找过程:从表的一端开始逐个进行记录的关键字和给定值的比较。 静态查找表的顺序存储结构表 typedef struct ElemType *elem; int length; SSTable; 顺序表的查找算法 int Search_Seq(SSTable ST,KeyType key) ST.elem0.key=key; for(i=ST.length;!EQ(ST.elemi.key),key);-i) return i;,8.1 静态查找表,64,监视哨,
3、比较次数 查找第n个元素: 1 查找第i个元素: n-i+1 查找失败: n+1,顺序查找方法的平均查找长度ASL:,比较次数=5,8.1.2 有序表的查找,折半查找:每次将待查记录所在区间缩小一半。 适用条件:采用顺序存储结构的有序表。算法实现:1.设表长为n,low、high和mid分别指向待查元素所在区间 的上界、下界和中点,k为给定值 。 2.初始时,令low=1,high=n,mid=(low+high)/2。 3.让k与mid指向的记录比较: 若k=rmid.key,查找成功。 若krmid.key,则low=mid+1。 4.重复上述操作,直至lowhigh时,查找失败。,折半查
4、找算法具体实现: int Search_Bin(SSTable ST, KeyType key) low=1;high=ST.length; while(lowhigh) mid=(low+high)/2; if(EQ(key,ST.elemmid.key)return mid; elseif (LT(key, ST.elemmid.key) high=mid-1; else low=mid+1; return 0; ,例:找70,判定树:为了分析二分查找的性能,可以用二叉树来描述二分查找过程:树中每个结点表示表中一个元素,结点中的值为该元素在表中的位置。把当前查找区间的中点作为根结点,左子区
5、间和右子区间分别作为根的左子树和右子树,左子区间和右子区间再按此方法类推,由此得到的二叉树称为二分查找的判定树。,找 21:比较次数 = 3,在树上 找 85:比较次数 = 3,不在树上,索引顺序表查找分块查找,查找过程:将表分成几块,块内无序,块间有序;先确定待查记录所在块,再在块内查找。 适用条件:分块有序表。算法实现:用数组存放待查记录。建立索引表, 每个索引表结点含有最大关键字域和指向本块第一个结点的指针。,找到,8.2 动态查找表,特点:表结构本身在查找中动态生成。 8.2.1二叉排序树(或二叉查找树),(1)定义:二叉排序树(Binary Sort Tree)或者是一棵空 树;或者
6、是具有下列性质的二叉树:1)若左子树不空,则左子树上所有结点的值均小于根 结点的值;若右子树不空,则右子树上所有结点的 值均大于等于根结点的值。2)左右子树也都是二叉排序树。,(2)二叉排序树查找过程:若二叉排树为空,则查找失败,否则,先拿根结点值与待查值进行比较,若相等,则查找 成功,若根结点值大于待查值,则进入左子树重复此步 骤,否则,进入右子树重复此步骤,若在查找过程中遇到二叉排序树的叶子结点时,还没有找到待找结点,则查找不成功。,(3)二叉排序树插入操作和构造,例: 10, 18, 3, 8, 12, 2, 7, 3,10,二叉排序树生成:从空树出发,经过一系列的查找、插入操作之后,可
7、生成一棵二叉排序树。中序遍历二叉排序树可得一有序序列。,(4)二叉排序树上的删除,要删除二叉排序树中的p结点,分三种情况: 1)p为叶子结点:只需修改p双亲f的左(或右)孩子指针为空。 2)p只有左子树或右子树:a)p只有左子树,用p的左孩子代替p,b) p只有右子树,用p的右孩子代替p,3)p左、右子树均非空: 沿p左子树的根C的右子树分支找到S,S的右子树为空,将S的左子树成为S的双亲Q的右子树,用S取代p,若C无右子树,用C取代p,8.3 哈希表,8.3.1 什么是哈希表,基本思想:在记录的存储地址和它的关键字之间建立一个确定的对应关系;这样,不经过比较,直接就能得到所查元素的查找方法。
8、,在记录的关键字与记录的存储地址之间建立的一种对应关系叫哈希函数。,哈希表:应用哈希函数,由记录的关键字确定记录在表中的地址,并将记录放入此地址,这样构成的表叫哈希表。 哈希查找:又叫散列查找,利用哈希函数进行查找的过程。,以编号作关键字, 构造哈希函数:H(key)=key H(1)=1 H(2)=2,以地区名作关键字,取地区名称第一个拼音字母的序号作哈希函数:H(Beijing)=2 H(Shanghai)=19,哈希函数只是一种映象,所以哈希函数的设定很灵活,只要使任何关键字的哈希函数值都落在表长允许的范围之内即可。 散列表的理想情形:每一个关键字对应一个唯一的地址。 冲突:两个不同的关
9、键字有可能对应同一个存储地址,这样,将导致后放的关键字无法存贮,即 key1key2,但H(key1)= H(key2),这种现象叫冲突。具有相同函数值的两个关键字,叫该哈希函数的同义词。冲突不可避免,只能尽量减少;因此冲突发生后,应该有处理冲突的方法。,8.3.2 哈希函数的构造方法,数字分析法 构造:对关键字进行分析,取关键字的若干位或其组合作哈希地址。 适用于关键字位数比哈希地址位数大,且可能出现的关键字事先知道的情况。,直接定址法 构造:取关键字或关键字的某个线性函数作哈希地址,即H(key)=key 或 H(key)=akey+b。 特点: 直接定址法所得地址集合与关键字集合大小相等
10、,不会发生冲突。 实际中能用这种哈希函数的情况很少。,例:有80个记录,关键字为8位十进制数,哈希地址为2位十进制数。,分析: 只取8只取1只取3、4只取2、7、5数字分布近乎随机 故取任意两位或两位与另两位的叠加作哈希地址。,平方取中法 构造:取关键字平方后中间几位作哈希地址。 适于不知道全部关键字情况。,折叠法 构造:将关键字分割成位数相同的几部分,然后取这几部分的叠加和(舍去进位)做哈希地址。 折叠法一般分为以下几个种类: 移位叠加:将分割后的几部分低位对齐相加。 间界叠加:从一端沿分割界来回折迭,然后对齐相加。 适于关键字位数很多,且每一位上数字分布大致均匀情况。,例:关键字为 :04
11、42205864,哈希地址位数为4。,移位叠加:,间界叠加:,除留余数法 构造:取关键字被某个不大于哈希表表长m的数p除后所得余数作哈希地址,即H(key)=key MOD p,pm。 特点:简单、常用,可与上述几种方法结合使用。 p的选取很重要;p选的不好,容易产生同义词。,随机数法 构造:取关键字的随机函数值作哈希地址,即 H(key)=random(key)。 适于关键字长度不等的情况。,8.3.3 处理冲突的方法,开放定址法 方法:当冲突发生时,形成一个探查序列;沿此序列逐个地址探查,直到找到一个空位置(开放的地址),将发生冲突的记录放到该地址中,即Hi=(H(key)+di)MOD
12、m,i=1,2,k(km-1)。 其中:H(key)哈希函数 m哈希表表长 di增量序列 分类: 线性探测再散列:di=1,2,3,m-1 二次探测再散列:di=1,-1,2,-2,3,k(km/2) 伪随机探测再散列:di=伪随机数序列,例:表长为11的哈希表中已填有关键字为17,60,29的记录,H(key)=key MOD 11,现有第4个记录,其关键字为38,按三种处理冲突的方法,将它填入表中。,(1) H(38)=38 MOD 11=5 冲突H1=(5+1) MOD 11=6 冲突H2=(5+2) MOD 11=7 冲突H3=(5+3) MOD 11=8 不冲突,38,(2) H(3
13、8)=38 MOD 11=5 冲突H1=(5+1) MOD 11=6 冲突H2=(5-1) MOD 11=4 不冲突,38,(3) H(38)=38 MOD 11=5 冲突设伪随机数序列为9, ,则:H1=(5+9) MOD 11=3 不冲突,38,再哈希法 方法:构造若干个哈希函数,当发生冲突时,计算下一个哈希地址,即:Hi=Rhi(key) i=1,2,k。 其中:Rhi不同的哈希函数,链地址法 方法:将所有关键字为同义词的记录存储在一个单链表中,并用一维数组存放头指针。,例:已知一组关键字(19,14,23,1,68,20,84,27,55,11,10,79)哈希函数为:H(key)=k
14、ey MOD 13,用链地址法处理冲突:,哈希查找过程:,8.3.4 哈希表的查找及其分析,例:已知一组关键字(19,14,23,1,68,20,84,27,55,11,10,79), 哈希函数为:H(key)=key MOD 13, 哈希表长为m=16,设每个记录的查找概率相等。,哈希查找分析,哈希查找过程仍是一个给定值与关键字进行比较的过程。 评价哈希查找效率仍要用ASL。与哈希函数处理冲突的方法。,用线性探测再散列处理冲突 即Hi=(H(key)+di) MOD m,H(55)=3 冲突,H1=(3+1)MOD16=4冲突,H2=(3+2)MOD16=5,H(79)=1 冲突,H1=(1
15、+1)MOD16=2冲突,H2=(1+2)MOD16=3冲突,H3=(1+3)MOD16=4冲突,H4=(1+4)MOD16=5冲突,H5=(1+5)MOD16=6冲突,H6=(1+6)MOD16=7冲突,H7=(1+7)MOD16=8冲突,H8=(1+8)MOD16=9,ASL=(1*6+2+3*3+4+9)/12=2.5,14,1,68,27,55,19,20,84,79,23,11,10,H(19)=6,H(14)=1,H(23)=10,H(1)=1 冲突,H1=(1+1) MOD16=2,H(68)=3,H(20)=7,H(84)=6 冲突,H1=(6+1)MOD16=7冲突,H2=(6+2)MOD16=8,H(27)=1 冲突,H1=(1+1)MOD16=2冲突,H2=(1+2)MOD16=3冲突,H3=(1+3)MOD16=4,H(11)=11,H(10)=10 冲突,H1=(10+1)MOD16=11冲突,H2=(10+2)MOD16=12,用链地址法处理冲突,ASL=(1*6+2*4+3+4)/12=1.75,