《集合与查找》PPT课件.ppt_第1页
《集合与查找》PPT课件.ppt_第2页
《集合与查找》PPT课件.ppt_第3页
《集合与查找》PPT课件.ppt_第4页
《集合与查找》PPT课件.ppt_第5页
已阅读5页,还剩171页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

集合 静态查找 哈希表 二叉查找树 B树和B树,第5章 集合与查找,1,集合基本概念,集合及其表示,集合是成员(对象或元素)的一个群集。集合中的成员可以是原子(单元素),也可以是集合。 集合的成员必须互不相同。 在算法与数据结构中所遇到的集合,其单元素通常是整数、字符、字符串或指针,且同一集合中所有成员具有相同的数据类型。,2,colour = red, orange, yellow, green, black, blue, purple, white name = “An”, “Cao”, “Liu”, “Ma”, “Peng”, “Wang”, “zhang” 集合中的成员一般是无序的,但在表示它时,常写在一个序列里。 常设定集合中的单元素具有线性有序关系,此关系可记作“”,表示“优先于”。 整数、字符和字符串都有一个自然线性顺序。指针也可依据其在序列中安排的位置给予一个线性顺序。,3,集合运算,4,用位向量实现集合抽象数据类型,当集合是全集合 0, 1, 2, , n 的一个子集,且 n是不大的整数时,可用位(0, 1)向量来实现集合。 当全集合是由有限的可枚举的成员组成的集合时,可建立全集合成员与整数 0, 1, 2, 的一一对应关系,用位向量来表示该集合的子集。,5,集合的位向量(bit Vector)类的定义 #include const int DefaultSize = 100; class Set private: int * bitVector; /集合的位向量数组 int MaxSize; /最大元素个数 public: Set ( int MaxSetSize = DefaultSize ); Set ( ) delete bitVector; ,6,void MakeEmpty ( ) /置空 for ( int i = 0; i MaxSize; i+ ) bitVectori = 0; int AddMember ( const int x ); /加 int DelMember ( const int x ); /删 Set ,7,用位向量实现集合时部分操作的实现 Set : Set (int MaxSetSize) : MaxSize (MaxSetSize) assert ( MaxSize 0 ); /判参数合理否 bitVector = new int MaxSize; /分配空间 assert ( bitVector != NULL ); for ( int i = 0; i MaxSize; i+ ) /置空集合 bitVectori = 0; ,0 0 0 0 0 0 0 0 0 0,0 9,8,int Set : Addmember ( const int x ) if ( x = 0 ,0 0 0 0 0 0 0 0 0 0,0 9,1,9,0 1 0 0 0 0 0 0 0 0,0 9,int Set : DelMember ( const int x ) if ( x = 0 ,0,10,void Set : operator = ( Set ,this,0 1 1 1 0 0 0 0 0 0 0,right,0 1 1 1 0 0 0 0 1 1 0,11,Set ,this,right,this,0 1 1 1 0 0 0 0 1 1 0,0 0 1 0 0 1 0 1 0 1 0,0 1 1 1 0 1 0 1 1 1 0,12,Set ,this,right,this,0 1 1 1 0 0 0 0 1 1 0,0 0 1 0 0 1 0 1 0 1 0,0 0 1 0 0 0 0 0 0 1 0,13,Set ,this,right,this,0 1 1 1 0 0 0 0 1 1 0,0 0 1 0 0 1 0 1 0 1 0,0 1 0 1 0 0 0 0 1 0 0,14,int Set : Contains ( const int x ) /判存在 assert ( x = 0 ,0 1 0 0 1 0 0 1 0 0,0 9,3,15,int Set : operator = ( Set ,this,right,0 0 1 1 0 0 0 0 1 1 0,0 0 1 0 0 1 0 1 0 1 0,i,16,int Set : SubSet ( Set ,this,right,0 0 1 1 0 0 0 0 1 1 0,0 0 1 0 0 1 0 1 0 1 0,0 0 0 1,i,17,若表中存在特定元素,称查找成功,应输出该元素。 - 否则,称查找不成功(也应输出失败标志或失败位置),查找表 查 找 查找成功 查找不成功 静态查找 动态查找 关键字 主关键字 次关键字,由同一类型的数据元素(或记录)构成的集合。,查询(Searching)特定元素是否在表中。,只查找,不改变集合内的数据元素。 既查找,又改变(增减)集合内的数据元素。 元素中某个数据项的值,可用来识别一个元素 可以唯一标识一个元素的关键字,例如“学号”,例如“性别”,识别若干元素的关键字,基本概念,18,对查找表常用的操作有哪些? 查询某个“特定的”数据元素是否在表中; 在查找表中插入一元素; 从查找表中删除一元素。,查找的过程是怎样的? 给定一个值K,在含有n个元素的查找表中寻找一个关键字值等于K的元素,可给出该元素在查找表中的位置, 还可给出该元素中的具体信息;如找到则输出该元素,否则输出查找不成功的信息。,19,如何评估查找算法的优劣?,查找的过程就是将给定的K值与查找表中各元素的关键字进行比较的过程。所以用比较次数的平均值来评估算法的优劣,称为平均查找长度(ASL:average search length)。,显然,ASL值越小,时间效率越高。,设查找第 i 个元素的概率为 pi , 查找到第 i 个元素所需比较次数为 ci , 则查找成功的平均查找长度:,20,顺序搜索 (Sequential Search),所谓顺序搜索, 又称线性搜索, 主要用于在线性结构中进行搜索。 顺序搜索从表的先端开始, 顺序用各对象的关键码与给定值x进行比较, 直到找到与其值相等的对象, 则搜索成功; 给出该对象在表中的位置。 若整个表都已检测完仍未找到关键码与x相等的对象, 则搜索失败。给出失败信息。,21,template int searchList : Search ( const Type ,22,顺序搜索的平均搜索长度,设搜索第 i 个元素的概率为 pi, 搜索到第 i 个元素所需比较次数为 ci, 则搜索成功的平均搜索长度:,在顺序搜索并设置“监视哨”情形: ci = i +1, i = 0, 1, , n-1,因此,23,在等概率情形,pi = 1/n, i = 1, 2, , n。,在搜索不成功情形,ASLunsucc = n+1.,顺序查找的优缺点: 优点:对表中元素没有要求 缺点: 平均查找长度较大,24,基于有序顺序表的折半搜索,设n个对象存放在一个有序顺序表中,并按其关键码从小到大排好了序。 折半搜索时, 先求位于搜索区间正中的对象的下标mid,用其关键码与给定值x比较: Elementmid.key = x,搜索成功; Elementmid.key x,把搜索区间缩小 到表的前半部分,继续折半搜索; Elementmid.key x,把搜索区间缩小 到表的后半部分,继续折半搜索。 如果搜索区间已缩小到一个对象,仍未找到想要搜索的对象,则搜索失败。,25,-1 0 1 3 4 6 8 10 12,6,0 1 2 3 4 5 6 7 8,搜索,low,mid,high,6,26,-1 0 1 3 4 6 8 10 12,5,0 1 2 3 4 5 6 7 8,搜索,low,mid,high,5,27,BinarySearch ( const Type ,28,template int orderedList : BinarySearch ( const Type /搜索失败 ,29,算法分析: orderT: 0 1 2 3 4 5 6 7 8 9 10 11 12 13,2 4 6 8 10 13 15 18 20 22 24 25 27 30,15,6,2,4,10,8,13,24,20,27,18,22,25,30,折半查找的判定树:比较次数不超过完全二叉树高度。,30,最多的比较次数不超过二叉树的高度:所以 最坏情况下的查找长度是: 折半查找成功的平均查找长度: 设查找任一元素的概率都相等,即:pi=1/n 在第k层上最多有2k-1 个结点,在第k层上的结点需 比较k次。所以:,31,可以用归纳法证明,这样,32,有序顺序表的折半搜索的判定树 ( 10, 20, 30, 40, 50, 60 ),10,50,=,=,=,=,=,=,30,20,40,60,ASLunsucc = (2*1+3*6)/7 = 20/7,ASLsucc = (1+2*2+ 3*3)/6 = 14/6,33,索引顺序表的查找(分块查找) 1. 概念:是顺序查找的一种改进。 索引项:(key,addr), key 是关键字,addr是地址。 索引表:由索引项构成的顺序表。,如何查找关键字为60的元素?,34,分块查找的算法思想: D=d1,d2,.,dn 1) 将数据集分为s个块 B1,B2, , Bs ; 2) 块间有序:当ij时,Bi中的任一元素小于Bj中的任 一元素; 3) 为每个Bi块设一索引项(keyi, addri); 4) s个索引项构成索引表; 5) 块内可有序可无序;,35,查找过程: (1)首先在索引表中查找,确定在哪个块中。 可以是折半查找,也可以是顺序查找。 (2)在块中查找。在块中查找只能是顺序查找。,36,4. 算法分析: 设在索引表中和块内都是顺序查找。(s是索引项的数目) 索引表中查找:ALSindex=(s+1)/2 块中查找: ALSlock=(n/s+1)/2 所以: ALSbs= (s+1)/2 + (n/s+1)/2 显然它与s 的取值有关。 当 时,ASL有最小值,例如 当n=28,s=24时,ASLbs=17, 而折半法为8, 顺序表为(28+1)/2=128.5,37,倒排表 (Inverted Index List),对包含有大量数据对象的数据表或文件进行搜索时,最常用的是针对对象的主关键码建立索引。主关键码可以唯一地标识该对象。用主关键码建立的索引叫做主索引。 主索引的每个索引项给出对象的关键码和对象在表或文件中的存放地址。 但在实际应用中有时需要针对其它属性进行搜索。例如,查询如下的职工信息: (1) 列出所有教师的名单;,对象关键码 key 对象存放地址 addr,38,(2) 已婚的女性职工有哪些人? 这些信息在数据表或文件中都存在,但都不是关键码,为回答以上问题,只能到表或文件中去顺序搜索,搜索效率极低。 因此,除主关键码外,可以把一些经常搜索的属性设定为次关键码,并针对每一个作为次关键码的属性,建立次索引。 在次索引中,列出该属性的所有取值,并对每一个取值建立有序链表,把所有具有相同属性值的对象按存放地址递增的顺序或按主关键码递增的顺序链接在一起。,39,次索引的索引项由次关键码、链表长度和链表本身等三部分组成。 例如,为了回答上述的查询,我们可以分别建立“性别”、“婚否”和“职务”次索引。,40,婚否次索引,次关键码 已婚 未婚 计 数 5 3 地址指针,指针 03 08 24 47 83 17 51 95,职务次索引,次关键码 教师 教务员 实验员 计 数 5 1 2 地址指针,指针 08 24 47 51 83 03 17 95,41,(1) 列出所有教师的名单; (2) 已婚的女性职工有哪些人? 通过顺序访问“职务”次索引中的“教师”链,可以回答上面的查询(1)。 通过对“性别”和“婚否”次索引中的“女性”链和“已婚”链进行求“交集”运算,就能够找到所有既是女性又已婚的职工对象,从而回答上面的查询(2)。,42,倒排表是次索引的一种实现。在表中所有次关键码的链都保存在次索引中,仅通过搜索次索引就能找到所有具有相同属性值的对象。 在次索引中记录对象存放位置的指针可以用主关键码表示: 可通过搜索次索引确定该对象的主关键码, 再通过搜索主索引确定对象的存放地址。,43,在倒排表中各个属性链表的长度大小不一,管理比较困难。为此引入单元式倒排表。 在单元式倒排表中, 索引项中不存放对象的存储地址, 存放该对象所在硬件区域的标识。 硬件区域可以是磁盘柱面、磁道或一个页块, 以一次 I / O 操作能存取的存储空间作为硬件区域为最好。,44,为使索引空间最小, 在索引中标识这个硬件区域时可以使用一个能转换成地址的二进制数, 整个次索引形成一个(二进制数的) 位矩阵。 例如,45,散列 (Hashing),在现实中经常遇到按给定的值进行查询的事例。为此, 必须考虑在记录的存放位置和用以标识它的数据项(称为关键码)之间的对应关系,选择适当的数据结构, 很方便地根据记录的关键码检索到对应记录的信息。 词典:查找、插入、删除 表项的存放位置及其关键码之间的对应关系可以用一个二元组表示: ( 关键码key,表项位置指针addr ) 这个二元组构成搜索某一指定表项的索引项。,46,静态散列方法,散列方法在表项存储位置与其关键码之间建立一个确定的对应函数关系Hash( ),使每个关键码与结构中一个唯一存储位置相对应: Address Hash ( Rec.key ) 在搜索时, 先对表项的关键码进行函数计算,把函数值当做表项的存储位置, 在结构中按此位置取表项比较。若关键码相等, 则搜索成功。在存放表项时, 依相同函数计算存储位置, 并按此位置存放。此方法称为散列方法。,47,直接定址法 此类函数取关键码的某个线性函数值作为散列地址: Hash ( key ) a * key + b a, b为常数 这类散列函数是一对一的映射,一般不会产生冲突。但是,它要求散列地址空间的大小与关键码集合的大小相同。,48,示例:有一组关键码如下: 942148, 941269, 940527, 941630, 941805, 941558, 942047, 940001 。散列函数为 Hash (key) = key - 940000 Hash (942148) = 2148 Hash (941269) = 1269 Hash (940527) = 527 Hash (941630) = 1630 Hash (941805) = 1805 Hash (941558) = 1558 Hash (942047) = 2047 Hash (940001) = 1 可以按计算出的地址存放记录。,49,数字分析法 设有 n 个 d 位数, 每一位可能有 r 种不同的符号。这 r 种不同符号在各位上出现的频率不一定相同。 可根据散列表的大小, 选取其中各种符号分布均匀的若干位作为散列地址。 计算各位数字中符号分布均匀度 k 的公式: 其中, 表示第 i 个符号在第 k 位上出现的次数,n/r 表示各种符号在 n 个数中均匀出现的期望值。计算出的 k 值越小,表明在该位 (第 k 位) 各种符号分布得越均匀。,50,9 4 2 1 4 8 位, 1 = 57.60 9 4 1 2 6 9 位, 2 = 57.60 9 4 0 5 2 7 位, 3 = 17.60 9 4 1 6 3 0 位, 4 = 5.60 9 4 1 8 0 5 位, 5 = 5.60 9 4 1 5 5 8 位, 6 = 5.60 9 4 2 0 4 7 9 4 0 0 0 1 ,若散列表地址范围有 3 位数字, 取各关键码的 位做为记录的散列地址。,51,除留余数法 设散列表中允许地址数为 m, 取一个不大于 m, 但最接近于或等于 m 的质数 p 作为除数, 或不含有小于20的质因数的合数作为除数,利用以下函数把关键码转换成散列地址: hash ( key ) = key % p p m,52,示例: 有一个关键码 key = 962148, 散列表大小 m = 25, 即 HT25。取质数 p= 23。散列函数 hash ( key ) = key % p。则散列地址为 hash ( 962148 ) = 962148 % 23 = 12。 可以按计算出的地址存放记录。需要注意的是, 使用上面的散列函数计算出来的地址范围是 0到 22, 因此, 从23到24这几个散列地址实际上在一开始是不可能用散列函数计算出来的, 只可能在处理冲突时达到这些地址。,53,平方取中法 它先计算构成关键码的标识符的内码的平方, 然后按照散列表的大小取中间的若干位作为散列地址。 在平方取中法中, 一般取散列地址为2的某次幂。例如, 若散列地址总数取为 m = 2r,则对内码的平方数取中间的 r 位。 r = 3,所取得的散列地址参看图的最右一列。,54,标识符 内码 内码的平方 散列地址 A 01 01 001 A1 0134 20420 042 A9 0144 23420 342 B 02 4 004 DMAX 04150130 21526443617100 443 DMAX1 0415013034 5264473522151420 352 AMAX 01150130 135423617100 236 AMAX1 0115013034 3454246522151420 652,标识符的八进制内码表示及其平方值,55,基数转换法 将关键字看作另一个基数制上的表示,然后把它转换成原来基数制的数,再用数字分析法取其中的几位作为地址。 如:key236075 ( 236075)13 213531346133 7135(841547)10 再选2、3、4、5位, h(236075)=4154,56,折叠法 把关键码自左到右分成位数相等的几部分, 每一部分的位数应与散列表地址位数相同, 只有最后一部分的位数可以短一些。 把这些部分的数据叠加起来, 就可以得到具有该关键码的记录的散列地址。 有两种叠加方法: 移位法 把各部分的最后一位对齐相加; 分界法 各部分不折断, 沿各部分的分界来回折叠, 然后对齐相加。,57,示例: 设给定的关键码为 key = 23938587841, 若存储空间限定 3 位, 则划分结果为每段 3 位。 上述关键码可划分为 4段: 239 385 878 41 把超出地址位数的最高位删去, 仅保留最低的3位,做为可用的散列地址。,移 位 法,385,878,41,1543,41,239,239,385,878,1714,分 界 法,58,一般当关键码的位数很多,而且关键码每一位上数字的分布大致比较均匀时,可用这种方法得到散列地址。 小结:以上介绍了几种常用的散列函数。在实际工作中应根据关键码的特点,选用适当的方法。有人曾用“轮盘赌”的统计分析方法对它们进行了模拟分析,结论是平方取中法最接近于“随机化”。,59,处理冲突的闭散列方法,为了减少冲突,改造散列表:若设散列表 HT 有 m 个地址, 将其改为 m 个桶。其桶号与散列地址一一对应, 第 i (0 i m) 个桶的桶号即为第 i 个散列地址。 每个桶可存放 s 个表项, 这些表项的关键码互为同义词。如果对两个不同表项的关键码用散列函数计算得到同一个散列地址,就产生了冲突,它们可以放在同一个桶内的不同位置。,60,只有当桶内所有 s 个表项位置都放满表项后再加入表项才会产生溢出。 通常桶的大小 s 取的比较小, 因此在桶内大多采用顺序搜索。 闭散列也叫做开地址法。在闭散列情形, 所有的桶都直接放在散列表数组中。因此每个桶只有一个表项 ( s = 1 )。,61,若设散列表中各桶的编址为 0 到 m-1, 当要加入一个表项 R2时, 用它的关键码 R2.key, 通过散列函数 hash ( R2.key ) 的计算,得到它的存放桶号 j。 但在存放时发现此桶已被另一个表项 R1 占据, 发生了冲突, 必须处理冲突。为此, 需把 R2 存放到表中“下一个”空桶中。 如果表未被装满, 则在允许的范围内必定还有空桶。,62,(1) 线性探查法 (Linear Probing),假设给出一组表项,它们的关键码为 Burke, Ekers, Broad, Blum, Attlee, Alton, Hecht, Ederly。采用的散列函数是:取其第一个字母在字母表中的位置。 Hash (x) = ord (x) - ord (A) /ord ( ) 是求字符内码的函数,63,可得 Hash (Burke) = 1 Hash (Ekers) = 4 Hash (Broad) = 1 Hash (Blum) = 1 Hash (Attlee) = 0 Hash (Hecht) = 7 Hash (Alton) = 0 Hash (Ederly) = 4 设散列表 HT26, m = 26。采用线性探查法处理冲突, 则散列结果如图所示。,0 1 2 3 4,Attlee Burke Broad Blum Ekers,Alton Ederly Hecht,5 6 7 8 9,(1) (1) (2) (3) (1),(6) (3) (1),64,需要搜索或加入一个表项时, 使用散列函数计算桶号: H0 = hash ( key ) 一旦发生冲突,在表中顺次向后寻找“下一 个”空桶 Hi 的递推公式为: Hi = ( Hi-1 +1 ) % m, i =1, 2, , m-1 即用以下的线性探查序列在表中寻找“下一 个”空桶的桶号: H0 +1, H0 +2, , m-1, 0, 1, 2, , H0-1 亦可写成如下的通项公式: Hi = ( H0 + i ) % m, i =1, 2, , m-1,65,线性探查方法容易产生“堆积”, 不同探查序列的关键码占据可用的空桶, 为寻找某一关键码需要经历不同的探查序列, 导致搜索时间增加。 为改善“堆积”问题, 减少为完成搜索所需的平均探查次数, 可使用二次探查法。,66,(2) 二次探查法 (quadratic probing),通过某一个散列函数对表项的关键码 x 进行计算, 得到桶号, 它是一个非负整数。 H0 = hash(x) 二次探查法在表中寻找“下一个”空桶的公式: Hi = (H0 + i 2 ) % m, Hi = (H0 - i 2 ) % m, i = 1, 2, , (m-1)/2 式中的 m 是表的大小,它应是一个值为 4k+3 的质数,其中 k 是一个整数。如 3, 7, 11, 19, 23, 31, 43, 59, 127, 251, 503, 。,67,探查序列如 H0, H0+1, H0-1, H0+4, H0-4, 。 在做 (H0 - i2 ) % m 的运算时, 当 H0 - i2 0 时, 运算结果也是负数。实际算式可改为 j = (H0 - i2 ) % m, if ( j 0 ) j += m 示例:给出一组关键码 Burke, Ekers, Broad, Blum, Attlee, Alton, Hecht, Ederly 。 散列函数为:Hash (x)ord (x)ord (A) 用它计算可得 Hash (Burke) = 1 Hash (Ekers) = 4 Hash (Broad) = 1 Hash (Blum) = 1 Hash (Attlee) = 0 Hash (Hecht) = 7 Hash (Alton) = 0 Hash (Ederly) = 4,68,因为可能桶号是 0 25, 取满足 4k+3 的质数,表的长度为TableSize = 31,利用二次探查法得到的散列结果如图所示。,0 1 2 3 4 5,Blum Burke Broad Ekers Ederly,Hecht,6 7 8 9 10 11,Alton Attlee,(3) (1) (2) (1) (2),(1),25 26 27 28 29 30,(5) (3),利用二次探查法处理溢出,69,(3) 双散列法,使用双散列方法时, 需要两个散列函数。 第一个散列函数 Hash( ) 按表项的关键码 key 计算表项所在的桶号 H0 = Hash(key)。 一旦冲突,利用第二个散列函数 ReHash( ) 计算该表项到达“下一个”桶的移位量。,70,若设表的长度为 m = TableSize,则在表中寻找“下一个”桶的公式为: j = H0 = Hash(key), p = ReHash(key); j = ( j + p ) % m; p是小于m且与m互质的整数 双散列法的探查序列也可写成: Hi = (H0 + i * ReHash(key) ) % m, i =1, 2, , m-1 利用双散列法, 按一定的距离, 跳跃式地寻找“下一个”桶, 减少了“堆积”的机会。,71,示例:给出一组表项关键码 22, 41, 53, 46, 30, 13, 01, 67 。散列函数为: Hash(x)(3x) % 11。 散列表为 HT010,m = 11。因此,再散列函数为 ReHash(x) = (7x) % 10 +1。,72,H0(22) = 0 H0(41) = 2 H0(53) = 5 H0(46) = 6 H0(30) = 2 冲突 H1 = (2+1) = 3 H0(13) = 6 冲突 H1 = (6+2) = 8 H0(01) = 3 冲突 H1 = (3+8) = 0 冲突 H2 = (0+8) = 8 冲突 H3 = (8+8) = 5 冲突 H4 = (5+8) = 2 冲突 H5 = (2+8) = 10 H0(67) = 3 冲突 H1 = (3+10) = 2 冲突 H2 = (2+10) = 1,73,处理冲突的开散列方法 链地址法,开散列方法首先对关键码集合用某一个散列函数计算它们的存放位置。 若设散列表地址空间的所有位置是从 0 到 m-1, 则关键码集合中的所有关键码被划分为m个子集, 具有相同地址的关键码归于同一子集。我们称同一子集中的关键码互为同义词。每一个子集称为一个桶。 通常各个桶中的表项通过一个单链表链接起来,称之为同义词子表。所有桶号相同的表项都链接在同一个同义词子表中,各链表的表头结点组成一个向量。,74,向量的元素个数与桶数一致。桶号为 i 的同义词子表的表头结点是向量中的第 i 个元素。 示例:给出一组表项关键码 Burke, Ekers, Broad, Blum, Attlee, Alton, Hecht, Ederly 。散列函数为:Hash (x)ord (x)ord (A)。 用它计算可得: Hash (Burke) = 1 Hash (Ekers) = 4 Hash (Broad) = 1 Hash (Blum) = 1 Hash (Attlee) = 0 Hash (Hecht) = 7 Hash (Alton) = 0 Hash (Ederly) = 4 散列表为 HT025,m = 26。,75,0 1 2 3 4 5 6 7 8 9,Attlee,Alton,Burke,Broad,Blum,Ekers,Ederly,Hecht,76,二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。 左子树(如果存在)上所有结点的关键码都小于根结点的关键码。 右子树(如果存在)上所有结点的关键码都大于根结点的关键码。 左子树和右子树也是二叉搜索树。,二叉搜索树 ( Binary Search Tree ),77,二叉搜索树例,如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各结点关键码排列起来,所以也称二叉搜索树为二叉排序树。,78,二叉链表,二叉搜索树的类定义,在二叉搜索树上进行搜索,是一个从根结点开始,沿某一个分支逐层向下进行比较判等的过程。它可以是一个递归的过程。,二叉搜索树上的搜索,79,假设想要在二叉搜索树中搜索关键码为x的元素,搜索过程从根结点开始。 如果根指针为NULL,则搜索不成功;否则用给定值x与根结点的关键码进行比较: 如果给定值等于根结点的关键码,则搜索成功。 如果给定值小于根结点的关键码,则继续递归搜索根结点的左子树; 否则,递归搜索根结点的右子树。,80,搜索45 搜索成功,搜索28 搜索失败,81,二叉搜索树的插入,28,每次结点的插入,都要从根结点出发搜索插入位置,然后把新结点作为叶结点插入。,插入新结点28,82,输入数据,建立二叉搜索树的过程,输入数据 53, 78, 65, 17, 87, 09, 81, 15 ,53,83,同样 3 个数据 1, 2, 3 ,输入顺序不同,建立起来的二叉搜索树的形态也不同。这直接影响到二叉搜索树的搜索性能。 如果输入序列选得不好,会建立起一棵单支树,使得二叉搜索树的高度达到最大。 2, 1, 3 1, 2, 3 1, 3, 2 2, 3, 1 3, 1, 2 3, 2, 1,84,二叉搜索树的删除,在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新链接起来,同时确保二叉搜索树的性质不会失去。 为保证在删除后树的搜索性能不至于降低,还需要防止重新链接后树的高度增加。 删除叶结点,只需将其双亲结点指向它的指针清零,再释放它即可。,85,删除45,被删结点右子树为空,可以拿它的左子女结点顶替它的位置,再释放它。,86,删除78,被删结点左子树为空,可以拿它的右子女结点顶替它的位置,再释放它。,87,删除78,被删结点左、右子树都不为空,可以在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删结点中,再来处理这个结点的删除问题。,88,AVL树 高度平衡的二叉搜索树,AVL树的定义,一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1。,89,结点的平衡因子 (balance factor),每个结点附加一个数字, 给出该结点右子树的高度减去左子树的高度所得的高度差,这个数字即为结点的平衡因子 。 AVL树任一结点平衡因子只能取 -1, 0, 1 如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡, 不再是AVL树。 如果一棵二叉搜索树是高度平衡的, 且有 n 个结点,其高度可保持在O(log2n),平均搜索长度也可保持在O(log2n)。,90,平衡化旋转,如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。 平衡化旋转有两类: 单旋转 (左旋和右旋) 双旋转 (左平衡和右平衡) 每插入一个新结点时, AVL 树中相关结点的平衡状态会发生改变。因此, 在插入一 个新结点后,需要从插入位置沿通向根的路径回溯,检查各结点的平衡因子。,91,如果在某一结点发现高度不平衡,停止回溯。从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。 如果这三个结点处于一条直线上,则采用单旋转进行平衡化。单旋转可按其方向分为左单旋转和右单旋转, 其中一个是另一 个的镜像,其方向与不平衡的形状相关。 如果这三个结点处于一条折线上,则采用双旋转进行平衡化。双旋转分为先左后右和先右后左两类。,92,右单旋转,左单旋转,左右双旋转,右左双旋转,93,在结点A的右子女的右子树E中插入新结点,该子树高度增1导致结点A的平衡因子变成2,出现不平衡。为使树恢复平衡,从A沿插入路径连续取3个结点A、C和E,以结点C为旋转轴,让结点A反时针旋转。,插入,左单 旋转,左单旋转 (RotateLeft ),94,h,在结点A的左子女的左子树D上插入新结点使其高度增1导致结点A的平衡因子增到-2,造成不平衡。为使树恢复平衡,从A沿插入路径连续取3 个结点A、B和D,以结点B为旋转轴,将结点A顺时针旋转。,插入,右单旋转 (RotateRight ),95,插入,在结点A的左子女的右子树中插入新结点,该子树的高度增1导致结点A的平衡因子变为-2,造成不平衡。以结点E为旋转轴,将结点B反时针旋转,以E代替原来B的位置。,先左后右双旋转 (RotationLeftRight),96,再以结点E为旋转轴,将结点A顺时针旋转。使之平衡化。,右单 旋转,97,先右后左双旋转 (RotationRightLeft),在结点A的左子女的右子树中插入新结点,该子树高度增1。结点A的平衡因子变为2,发生了不平衡。以结点D为旋转轴,将结点C顺时针旋转,以D代替原来C的位置。,98,再以结点D为旋转轴,将结点A反时针旋转,恢复树的平衡。,99,AVL树的插入,在向一棵本来是高度平衡的AVL树中插入一个新结点时,如果树中某个结点的平衡因子的绝对值 |balance| 1,则出现了不平衡,需要做平衡化处理。 算法从一棵空树开始,通过输入一系列对象关键码,逐步建立AVL树。在插入新结点时使用平衡旋转方法进行平衡化处理。,100,例,输入关键码序列为 16, 3, 7, 11, 9, 26, 18, 14, 15 ,插入和调整过程如下。,101, 16, 3, 7, 11, 9, 26, 18, 14, 15 ,102,15,18,2,3,18,16,-2,左右双旋,7,3,0,0,0,11,7,14,9,-1,16,15,0,1,11,26,26,14,1,-2,9,103,AVL树的删除,(1) 如果被删结点x最多只有一个子女,那么问题比较简单: 将结点x从树中删去。 因为结点x最多有一个子女,可以简单地把x的双亲结点中原来指向x的指针改指到这个子女结点; 如果结点x没有子女,x双亲结点的相应指针置为NULL。 将原来以结点x为根的子树的高度减1。,104,(2) 如果被删结点x有两个子女: 搜索 x 在中序次序下的直接前驱 y (同样可以找直接后继)。 把 结点y 的内容传送给结点x,现在问题转移到删除结点 y。把结点y当作被删结点x。 结点y最多有一个子女,我们可以简单地用(1)给出的方法进行删除。,105,case 1 : 当前结点 p 的balance为0。如果它的左子树或右子树被缩短,则它的 balance改为 1 或-1。,0,h,h,h-1,删除一个结点,高度降低一层,不旋转,1,h,h-1,p,p,106,case 2 : 结点 p 的balance不为0,且较高的子树被缩短,则 p 的balance改为0。,-1,h+1,h,h,删除一个结点,高度降低一层,不旋转,0,h,h,p,p,高度减1,107,case 3 : 结点 p 的balance不为0,且较矮的子树又被缩短,则在结点 p 发生不平衡。需要进行平衡化旋转来恢复平衡。 令 p 的较高的子树的根为 q (该子树未被缩短), 根据 q 的balance,有如下 3 种平衡化操作。 在case 3a, 3b和3c的情形中,旋转的方向取决于是结点 p 的哪一棵子树被缩短。,108,case 3a : 如果 q (较高的子树) 的balance为 0,执行一个单旋转来恢复结点 p 的平衡。,1,h,h,h-1,删除结点,左单旋,p,h,0,q,1,h,h-1,p,h,q,-1,109,case 3b : 如果 q 的balance与 p 的balance相同,则执行一个单旋转来恢复平衡, 结点 p 和 q 的balance均改为0。,1,h,h-1,删除结点,左单旋,p,h,1,q,0,h-1,p,h,q,0,h-1,h-1,110,0,case 3c : 如果 p 与 q 的balance相反, 则执行一个双旋转来恢复平衡, 先围绕 q 转再围绕 p 转。新根结点的balance置为0,其他结点的balance相应处理。,1,h,h-1,删除 结点,p,-1,q,h-1 或 h-2,h-1 或 h-2,h-1,r,h-1,h-1,h-1,h-1,0,0,p,q,r,右左双旋,高度减1,111,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,树的初始状态,举例,112,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,0,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,删除结点P,寻找结点P在中序下的直接前驱O, 用O顶替P, 删除O。,用O取代P,113,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,Q,R,S,T,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,删除结点P,左单旋转,以R为旋转轴做左单旋转, M的子树高度减 1。,114,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,Q,R,S,T,0,0,0,0,0,0,-1,-1,-1,-1,-1,-1,-1,1,0,0,1,删除结点P,M的子树高度减 1, M发生不平衡。M与E的平衡因子反号, 做左右双旋转。,0,向上继续调整,115,A,B,C,D,E,F,G,H,I,J,N,K,L,M,O,R,0,0,0,0,0,-1,0,0,-1,-1,-1,-1,0,1,0,0,删除结点P,0,0,T,Q,0,S,116,现在我们所讨论的 m 路搜索树多为可以动态调整的多路搜索树,它的递归定义为: 一棵 m 路搜索树, 它或者是一棵空树, 或者是满足如下性质的树: 根最多有 m 棵子树, 并具有如下的结构: ( n, P0, K1, P1, K2, P2, , Kn, Pn ) 其中, Pi 是指向子树的指针, 0 i n m; Ki 是关键码, 1 i n m。 Ki Ki+1, 1 i n。,动态的 m 路搜索树,117,在子树 Pi 中所有的关键码都小于 Ki+1, 且大于 Ki,0 i n。 在子树 Pn 中所有的关键码都大于Kn; 在子树 P0 中的所有关键码都小于 K1。 子树 Pi 也是 m 路搜索树,0 i n。,一棵3路搜索树的示例,35,20 40,a,b,c,d,e,25 30,10 15,45 50,118,m 路搜索树上的搜索算法,在 m 路搜索树上的搜索过程是一个在结点内搜索和沿指针向下搜索的交替的过程。,搜索35,119,提高搜索树的路数 m, 可以改善树的搜索性能。对于给定的关键码数 n,如果搜索树是平衡的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论