收藏 分享(赏)

数据结构7搜索结构.ppt

上传人:saw518 文档编号:6213651 上传时间:2019-04-02 格式:PPT 页数:74 大小:957.50KB
下载 相关 举报
数据结构7搜索结构.ppt_第1页
第1页 / 共74页
数据结构7搜索结构.ppt_第2页
第2页 / 共74页
数据结构7搜索结构.ppt_第3页
第3页 / 共74页
数据结构7搜索结构.ppt_第4页
第4页 / 共74页
数据结构7搜索结构.ppt_第5页
第5页 / 共74页
点击查看更多>>
资源描述

1、第七章 搜索结构,本章要点:静态搜索表的顺序搜索与折半搜索二叉搜索树的表示、搜索、插入、删除算法AVL树的平衡化及相应算法,静态搜索表,搜索(Search)的概念,所谓搜索,就是在数据集合中寻找满足某种条件的数据对象。搜索的结果通常有两种可能:搜索成功,即找到满足条件的数据对象。这时,作为结果,可报告该对象在结构中的位置,还可进一步给出该对象中的具体信息。搜索不成功,或搜索失败。作为结果,也应报告一些信息,如失败标志、失败位置等。通常称用于搜索的数据集合为搜索结构,它是 由同一数据类型的对象(或记录)组成。,在每一个对象中有若干属性,其中应当有一个属性,其值可唯一地标识这个对象。它称为关键码。

2、使用基于关键码的搜索,搜索结果应是唯一的。但在实际应用时,搜索条件是多方面的,这样,可以使用基于属性的搜索方法,但搜索结果可能不唯一。 实施搜索时有两种不同的环境。静态环境,搜索结构在执行插入和删除等操作的前后不发生改变。 静态搜索表动态环境,为保持较高的搜索效率,搜索结构在执行插入和删除等操作的前后将自动进行调整,结构可能发生变化。 动态搜索表,静态搜索表结构,template class dataList; template class Node friend class dataList; public:Node ( const Type ,template class dataList

3、 public:dataList ( int sz = 10 ) : ArraySize (sz), Element (new Node sz) virtual dataList ( ) delete Element; friend ostream ,template class searchList : public dataList /作为派生类的静态搜索表的类定义 public: searchList ( int sz = 10 ) : dataList (sz) virtual searchList ( ) virtual int Search ( const Type ,templa

4、te istream ,template ostream ,衡量一个搜索算法的时间效率的标准是:在搜索过程中关键码的平均比较次数或平均读写磁盘次数(只适合于外部搜索),这个标准也称为平均搜索长度ASL(Average Search Length),通常它是搜索结构中对象总数m 或文件结构中物理块总数 n 的函数。 另外衡量一个搜索算法还要考虑算法所需要的存储量和算法的复杂性等问题。在静态搜索表中,数据对象存放于数组中,利用数组元素的下标作为数据对象的存放地址。搜索算法根据给定值x,在数组中进行搜索。直到找到x在数组中的存放位置或可确定在数组中找不到x为止。,顺序搜索 (Sequential S

5、earch),所谓顺序搜索,又称线性搜索,主要用于在线性结构中进行搜索。设若表中有 CurrentSize 个对象,则顺序搜索从表的先端开始,顺序用各对象的关键码与给定值x进行比较,直到找到与其值相等的对象,则搜索成功,给出该对象在表中的位置。若整个表都已检测完仍未找到关键码与x相等的对象,则搜索失败。给出失败信息。,template int searchList : Search ( const Type ,const int Size = 10; main ( ) /顺序搜索的主过程 searchList List1 (Size);float Target; int Location;ci

6、n List1; cout Target;if ( ( Location = List1.search (Target ) ) != 0 )cout “ 找到下标 ” Location endl;else cout “ 没有找到.n”; ,顺序搜索的平均搜索长度,设搜索第 i 个元素的概率为 pi,搜索到第 i 个元素所需比较次数为 ci,则搜索成功的平均搜索长度:,在顺序搜索情形,ci = i +1, i = 0, 1, , n-1,因此,在等概率情形,pi = 1/n, i = 0, 1, , n-1。,基于有序顺序表的折半搜索,设n个对象存放在一个有序顺序表中,并按其关键码从小到大排好了

7、序。 采用对分搜索时,先求位于搜索区间正中的对象的下标mid,用其关键码与给定值x比较:Elementmid.getKey( ) = x,搜索成功;Elementmid.getKey( ) x,把搜索区间缩小到表的前半部分,再继续进行对分搜索;Elementmid.getKey( ) x,把搜索区间缩小到表的后半部分,再继续进行对分搜索。 每比较一次,搜索区间缩小一半。如果搜索区间已缩小到一个对象,仍未找到想要搜索的对象,则搜索失败。,template class orderedList : public dataList /有序表的类定义,继承了数据表 public: orderedList

8、 (int sz = 10) : dataList (sz) virtual orderedList ( ) virtual int Search ( const Type ,template int orderedList : BinarySearch ( const Type ,template in orderedList : BinarySearch ( const Type ,从有序表构造出的二叉搜索树(判定树),若设 n = 2h-1,则描述对分搜索的二叉搜索树是高度为 h-1 的满二叉树。2h = n+1, h = log2(n+1)。第0层结点有1个,搜索第0层结点要比较1次;

9、第1层结点有2个,搜索第1层结点要比较2次;,,第 i (0 i h) 层结点有 2i 个,搜索第 i 层结点要比较 i+1次,。假定每个结点的搜索概率相等,即pi = 1/n,则搜索成功的平均搜索长度为,二叉搜索树 ( Binary Search Tree ),二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 每个结点都有一个作为搜索依据的关键码(key),所有结点的关键码互不相同。 左子树(如果存在)上所有结点的关键码都小于根结点的关键码。 右子树(如果存在)上所有结点的关键码都大于根结点的关键码。 左子树和右子树也是二叉搜索树。,如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺

10、序,将各结点关键码排列起来,所以也称二叉搜索树为二叉排序树。,二叉搜索树的类定义#include template class BST; template Class BstNode : public BinTreeNode /二叉搜索树结点类 friend class BST ; public:BstNode ( ) : leftChild (NULL) ,BstNode ( const Type d ) : data (d), rightChild (NULL) ,BstNode ( const Type d = 0, BstNode *L = NULL, BstNode *R = NUL

11、L) : data (d), leftChild (L),rightChild (R) BstNode ( ) ,protected:Type data; BstNode *leftChild, *rightChild; ;template class BST : public : BinaryTree private: BstNode *root; /二叉搜索树的根指针Type RefValue; /数据输入停止的标志BstNode *lastfound; /最近搜索到的结点的指针void MakeEmpty ( BstNode *,void Insert ( const Type /求最大

12、,friend class BSTIterator; /中序游标类 public:BST ( ) : root (NULL) BST ( Type value ) : RefValue (value), root (NULL) BST ( ); const BST ,Type Min ( ) return Min ( root )data ;Type Max ( ) return Max ( root )data ;void Insert ( const Type ,二叉搜索树上的搜索,在二叉搜索树上进行搜索,是一个从根结点开始,沿某一个分支逐层向下进行比较判等的过程。它可以是一个递归的过程。

13、 假设想要在二叉搜索树中搜索关键码为x的元素,搜索过程从根结点开始。如果根指针为NULL,则搜索不成功;否则用给定值x与根结点的关键码进行比较: 如果给定值等于根结点的关键码,则搜索成功。 如果给定值小于根结点的关键码,则继续递归搜索根结点的左子树; 否则。递归搜索根结点的右子树。,template BstNode * BST : Find (const Type /相等,搜索成功 ,template BstNode * BST : Find (const Type /搜索失败 ,每次结点的插入,都要从根结点出发搜索插入位置,然后把新结点作为叶结点插入。,二叉搜索树的插入,为了向二叉搜索树中插

14、入一个新元素,必须先检查这个元素是否在树中已经存在。 在插入之前,先使用搜索算法在树中检查要插入元素有还是没有。搜索成功: 树中已有这个元素,不再插入。搜索不成功: 树中原来没有关键码等于给定值的结点,把新元素加到搜索操作停止的地方。,template void BST: Insert (const Type ,输入数据,建立二叉搜索树的过程,输入数据序列 53, 78, 65, 17, 87, 09, 81, 45, 23 ,template BST : BST ( Type value ) /输入数据,建立二叉搜索树的算法, RefValue是 /输入结束标志Type 从空树开始建树,输入

15、序列以输入一个结束标志value结束。这个值应当取不可能在输入序列中出现的值,例如输入序列的值都是正整数时,取RefValue为0或负数。,同样 3 个数据 1, 2, 3 ,输入顺序不同,建立起来的二叉搜索树的形态也不同。这直接影响到二叉搜索树的搜索性能。如果输入序列选得不好,会建立起一棵单支树,使得二叉搜索树的高度达到最大,这样必然会降低搜索性能。2, 1, 3 1, 2, 3 1, 3, 2 2, 3, 1 3, 1, 2 3, 2, 1,1,2,3,1,1,1,1,2,2,2,2,3,3,3,3,二叉搜索树的删除,在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新链接起

16、来,同时确保二叉搜索树的性质不会失去。为保证在执行删除后,树的搜索性能不至于降低,还需要防止重新链接后树的高度增加。 删除叶结点,只需将其双亲结点指向它的指针清零,再释放它即可。 被删结点缺右子树,可以拿它的左子女结点顶替它的位置,再释放它。 被删结点缺左子树,可以拿它的右子女结点顶替它的位置,再释放它。,被删结点左、右子树都存在,可以在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删结点中,再来处理这个结点的删除问题。二叉搜索树的删除算法,template void BST : Remove (const Type ,else if ( ptrleftChild != N

17、ULL ,最优二叉搜索树,对于有 n 个关键码的集合,其关键码有 n! 种不同的排列,可构成的不同二叉搜索树有(棵),如何评价这些二叉搜索树,可以用树的搜索效率来衡量。 例如,已知关键码集合 a1, a2, a3 = do, if, to ,对应搜索概率为 p1=0.5, p2=0.1, p3=0.05, 在各个搜索不成功的间隔内搜索概率又分别为 q0=0.15, q1=0.1, q2=0.05, q3=0.05。可能的二叉搜索树如下所示。,3个结点的5种不同的(扩充)二叉树,在扩充二叉搜索树中表示内部结点,包含了关键码集合中的某一个关键码;表示外部结点,代表造成搜索失败的各关键码间隔中的不在

18、关键码集合中的关键码。 在每两个外部结点之间必然存在一个内部结点。,设二叉树的内部结点有 n 个,外部结点有 n+1 个。如果定义每个结点的路径长度为该结点的层次,并用 I 表示所有 n 个内部结点的路径长度之和,用 E 表示 n+1 个外部结点的路径长度之和,可以用归纳法证明,E = I+2n。一棵扩充二叉搜索树的搜索成功的平均查找长度ASLsucc可以定义为该树所有内部结点上的权值pi与搜索该结点时所需的关键码比较次数ci (= li + 1)乘积之和:,扩充二叉搜索树搜索不成功的平均搜索长度ASLunsucc为树中所有外部结点上权值qj与到达外部结点所需关键码比较次数cj(= lj)乘积

19、之和:,扩充二叉搜索树总的平均搜索长度为:ASL = ASLsucc + ASLunsucc所有内、外部结点上的权值关系为,(1) 相等搜索概率的情形,若设树中所有内、外部结点的搜索概率都相等:pi = qj = 1/7,1 i 3, 0 j 3图(a):ASLsucc = 1/7*3+1/7*2+1/7*1 = 6/7,ASLunsucc = 1/7*3*2+1/7*2+1/7*1 = 9/7。总平均搜索长度 ASL = 6/7 + 9/7 = 15/7。,图(a): ASL = 15/7 图(d):ASL = 15/7图(b):ASL = 13/7 图(e):ASL = 15/7图(c):

20、ASL = 15/7图(b)的情形所得的平均搜索长度最小。一般把平均搜索长度达到最小的扩充二叉搜索树称作最优二叉搜索树,,在相等搜索概率的情形下,因为所有内部结点、外部结点的搜索概率都相等,把它们的权值都视为 1。同时,第 k 层有 2k 个结点,k = 0, 1, 。则有 n 个内部结点的扩充二叉搜索树的内部路径长度 I 至少等于序列0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 的前n项的和。因此,最优二叉搜索树的搜索成功的平均搜索长度和搜索不成功的平均搜索长度分别为:,(2) 不相等搜索概率的情形,设树中所有内、外部结点的搜索概率互不

21、相等,p1 = 0.5,p2 = 0.1,p3 = 0.05q0 = 0.15,q1 = 0.1,q2 = 0.05,q3 = 0.05图(a):ASLsucc = 0.5*3 + 0.1*2 + 0.05*1 = 1.75,ASLunsucc = 0.15*3 + 0.1*3 + 0.05*2 + 0.05*1= 0.9。ASL = ASLsucc + ASLunsucc = 2.65。图(a):ASL = 2.65 图(d):ASL = 2.15图(b):ASL = 1.9 图(e):ASL = 1.6图(c):ASL = 0.85 由此可知,图(c)的情形下树的平均搜索长度达到最小,因此

22、,图(c)的情形是最优二叉搜索树。,不相等搜索概率情形下的最优二叉搜索树可能不同于完全二叉树的形态。考虑在不相等搜索概率情形下如何构造最优二叉搜索树。假设关键码集合放在一个有序的顺序表中 key1, key2, key3,keyn 设最优二叉搜索树为T0n,其平均搜索长度为:,l i是内部结点 ai 所在的层次号,l j 是外部结点 j 所在的层次号。C0n 是树的代价。为计算方便,将 pi 与 qj 化为整数。,AVL树 高度平衡的二叉搜索树,AVL树的定义,一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1,高

23、度不平衡的二叉搜索树 高度平衡的二叉搜索树,结点的平衡因子balance (balance factor),每个结点附加一个数字,给出该结点右子树的高度减去左子树的高度所得的高度差。这个数字即为结点的平衡因子balance 。 根据AVL树的定义,任一结点的平衡因子只能取 -1,0和 1。 如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡,不再是AVL树。 如果一棵二叉搜索树是高度平衡的,它就成为 AVL树。如果它有 n 个结点,其高度可保持在O(log2n),平均搜索长度也可保持在O(log2n)。,AVL树的类定义,template class AVLTree publi

24、c:struct AVLNode Type data;AVLNode *left, *right;int balance;AVLNode ( ) : left (NULL), right (NULL), balance (0) AVLNode ( Type d, AVLNode *l = NULL,AVLNode *r = NULL ) : data (d), left (l), right (r), balance (0) ;,protected:Type RefValue; AVLNode *root; int Insert ( AVLNode* ,int Depth ( AVLNode

25、*t ) const; public:AVLTree ( ) : root (NULL) AVLNode ( Type Ref ) : RefValue (Ref), root (NULL) int Insert ( Type x ) int taller; return Insert ( root, x, taller ); friend istream ,平衡化旋转,如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。 平衡化旋转有两类:单旋转 (左旋和右旋)双旋转 (左平衡和右平衡) 每插入一个新结点时,AVL树中相关结点的平衡状态会发生改变。因此

26、,在插入一个新结点后,需要从插入位置沿通向根的路径回溯,检查各结点的平衡因子(左、右子树的高度差)。 如果在某一结点发现高度不平衡,停止回溯。,从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。 如果这三个结点处于一条直线上,则采用单旋转进行平衡化。单旋转可按其方向分为左单旋转和右单旋转,其中一个是另一个的镜像,其方向与不平衡的形状相关。 如果这三个结点处于一条折线上,则采用双旋转进行平衡化。双旋转分为先左后右和先右后左两类。,右单旋转,左单旋转,左右双旋转,右左双旋转,左单旋转 (RotateLeft ),h,h,h,A,C,E,B,D,(a) (b) (c),h,h,h + 1,B

27、,A,C,E,D,h,h,h + 1,C,E,A,B,D,如果在子树E中插入一个新结点,该子树高度增1导致结点A的平衡因子变成+2,出现不平衡。 沿插入路径检查三个结点A、C和E。它们处于一条方向为“”的直线上,需要做左单旋转。 以结点C为旋转轴,让结点A反时针旋转。,+1,+2,0,+1,0,0,右单旋转 (RotateRight ),h,h,h,A,C,E,B,D,(a) (b) (c),h,h + 1,B,A,C,E,D,h,h,h + 1,C,E,A,B,D,在左子树D上插入新结点使其高度增1,导致结点A的平衡因子增到 -2,造成了不平衡。 为使树恢复平衡,从A沿插入路径连续取3个结点

28、A、B和D,它们处于一条方向为“/”的直线上,需要做右单旋转。 以结点B为旋转轴,将结点A顺时针旋转。,h,0,0,0,-1,-1,-2,先左后右双旋转 (RotationLeftRight),在子树F或G中插入新结点,该子树的高度增1。结点A的平衡因子变为 -2,发生了不平衡。 从结点A起沿插入路径选取3个结点A、B和E,它们位于一条形如“”的折线上,因此需要进行先左后右的双旋转。 首先以结点E为旋转轴,将结点B反时针旋转,以E代替原来B的位置,做左单旋转。 再以结点E为旋转轴,将结点A顺时针旋转,做右单旋转。使之平衡化。,插入,左单 旋转,右单 旋转,0,0,-1,-2,+1,-1,0,0

29、,+1,先右后左双旋转 (RotationRightLeft),右左双旋转是左右双旋转的镜像。 在子树F或G中插入新结点,该子树高度增1。结点A的平衡因子变为2,发生了不平衡。 从结点A起沿插入路径选取3个结点A、C和D,它们位于一条形如“”的折线上,需要进行先右后左的双旋转。 首先做右单旋转:以结点D为旋转轴,将结点C顺时针旋转,以D代替原来C的位置。 再做左单旋转:以结点D为旋转轴,将结点A反时针旋转,恢复树的平衡。,左单 旋转,插入,右单旋转,+1,0,0,0,0,-1,-1,+1,+2,AVL树的插入,在向一棵本来是高度平衡的AVL树中插入一个新结点时,如果树中某个结点的平衡因子的绝对

30、值 |balance| 1,则出现了不平衡,需要做平衡化处理。 在AVL树上定义了重载操作“”和“”,以及中序遍历的算法。利用这些操作可以执行AVL树的建立和结点数据的输出。算法从一棵空树开始,通过输入一系列对象的关键码,逐步建立AVL树。在插入新结点时使用了前面所给的算法进行平衡旋转。,16,16,例,输入关键码序列为 16, 3, 7, 11, 9, 26, 18, 14, 15 ,插入和调整过程如下。,0,3,16,3,-1,0,7,0,1,-2,左右双旋,7,3,16,0,0,0,7,3,11,0,-1,1,7,3,16,16,11,9,0,-1,-2,右单旋,3,7,16,9,0,0

31、,0,1,3,7,11,26,9,16,11,0,1,1,2,2,18,18,0,3,16,3,-1,0,16,0,2,右左双旋,7,3,9,0,0,0,18,26,11,-1,7,3,26,16,11,9,-1,左单旋,9,7,16,14,0,0,1,7,11,26,26,9,1,1,11,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,从空树开始的建树过程,AVL树的删除,如果被删结点x最多只有一个子女,那么问题比较简单。如果被删结点x有两个子女,首先搜索 x 在中序次序下的直接前驱 y

32、 (同样可以找直接后继)。再把 结点y 的内容传送给结点x,现在问题转移到删除结点 y。把结点y当作被删结点x。 将结点x从树中删去。因为结点x最多有一个子女,我们可以简单地把x的双亲结点中原来指向x的指针改指到这个子女结点;如果结点x没有子女,x双亲结点的相应指针置为NULL。然后将原来以结点x为根的子树的高度减1,,case 1 : 当前结点 p 的balance为0。如果它的左子树或右子树被缩短,则它的 balance改为 1 或-1, case 2 : 结点 p 的balance不为0,且较高的子树被缩短,则 p 的balance改为0,case 3 : 结点 p 的balance不为

33、0,且较矮的子树又被缩短,则在结点 p 发生不平衡。需要进行平衡化旋转来恢复平衡。令 p 的较高的子树的根为 q (该子树未被缩短), 根据 q 的balance,有如下 3 种平衡化操作。 case 3a : 如果 q 的balance为0,执行一个单旋转来恢复结点 p 的平衡 case 3b : 如果 q 的balance与 p 的balance相同,则执行一个单旋转来恢复平衡,结点 p 和 q 的balance均改为0 case 3c : 如果 p 与 q 的balance相反,则执行一个双旋转来恢复平衡,先围绕 q 转再围绕 p 转。新的根结点的balance置为0,其它结点的bala

34、nce相应处理 在case 3a, 3b和3c的情形中,旋转的方向取决于是结点 p 的哪一棵子树被缩短。,AVL树的高度,设在新结点插入前AVL树的高度为 h,结点个数为 n,则插入一个新结点的时间是O(h)。对于AVL树来说,h 多大? 设 Nh 是高度为 h 的AVL树的最小结点数。根的一棵子树的高度为 h-1,另一棵子树的高度为 h-2,这两棵子树也是高度平衡的。因此有N-1 = 0 (空树)N0 = 1 (仅有根结点)Nh = Nh-1 + Nh-2 +1 , h 0 可以证明,对于 h 0,有 Nh = Fh+3 -1 成立。,有 n 个结点的AVL树的高度不超过在AVL树删除一个结点并做平衡化旋转所需时间为 O(log2n)。 二叉搜索树适合于组织在内存中的较小的索引(或目录)。对于存放在外存中的较大的文件系统,用二叉搜索树来组织索引不太合适。 在文件检索系统中大量使用的是用B_树或B+树做文件索引。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 网络科技 > 数据结构与算法

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报