数据结构第7章集合与搜索

上传人:文*** 文档编号:71324950 上传时间:2022-04-07 格式:DOC 页数:24 大小:400KB
返回 下载 相关 举报
数据结构第7章集合与搜索_第1页
第1页 / 共24页
数据结构第7章集合与搜索_第2页
第2页 / 共24页
数据结构第7章集合与搜索_第3页
第3页 / 共24页
点击查看更多>>
资源描述
第7章 集合与搜索一、复习要点集合是最基本的抽象数据类型之一。本章讨论了集合的三种存储表示:位数组表示、有序链表表示、并查集。在本章的后半部分,讨论了与集合相关的搜索方法和简单的性能分析方法,包括适用于静态搜索表的顺序搜索和折半搜索及代表动态搜索表的二叉搜索树和AVL树。可以使用扩充的二叉搜索树描述顺序搜索和折半搜索,从而推导出估算搜索效率的公式。静态搜索表在整个程序的运行期间结构不会变化,其搜索效率随着表中对象的个数n不断增长。动态搜索表因各个对象的输入顺序不同,得到的搜索表的形态不同,典型的是二叉搜索树。在具有n个对象的二叉搜索树中,搜索效率最高的是高度最低的二叉搜索树。为确保二叉搜索树始终保持搜索效率最高,必须在输入新的对象时判断二叉搜索树是否“失去平衡”,并进行适当的平衡旋转,使二叉搜索树的高度降到最低。这就是AVL树。在AVL树的讨论中,4种平衡旋转,选择参加平衡旋转的3个结点是关键,必须加以注意。本章复习的要点是:1、基本知识点必须理解集合及其表示方法,包括位数组表示、有序链表表示及其相关操作的实现算法集合及其表示。理解并查集实现的方法。理解搜索的概念,理解静态搜索表结构,掌握静态搜索表的顺序搜索和折半搜索算法及其性能分析方法。掌握二叉搜索树的表示、搜索、插入、删除算法及其性能分析方法,掌握AVL树的构造、插入、删除时的调整方法及其性能分析,重点是AVL树的定义、平衡化旋转、AVL树的插入和删除、AVL树的高度。2、算法设计 用有序链表表示集合时的求集合的并、交、差的算法 并查集中的构造函数、求根及合并算法 并查集中根据树的高度和根据树中结点个数进行合并的算法 设置监视哨的顺序搜索算法和不设监视哨的顺序搜索算法 有序顺序表的顺序搜索算法 有序顺序表的折半搜索的递归算法和非递归算法 二叉搜索树的搜索、插入和删除算法 计算AVL树中指定结点高度的递归算法及利用此算法计算结点平衡因子的算法二、难点和重点1、集合的概念:集合的基本运算、集合的存储表示 用位数组表示集合时集合基本运算的实现 用有序链表表示集合时集合基本运算的实现2、 并查集:并查集定义、并查集的三种基本运算的实现3、基本搜索方法 对一般表的顺序搜索算法(包括有监视哨和没有监视哨) 对有序顺序表的顺序搜索算法,包括递归和非递归算法 用判定树(即扩充二叉搜索树)描述有序顺序表的顺序搜索,以及平均搜索长度(成功与不成功)的计算。 对有序顺序表的折半搜索算法、包括递归和非递归算法 用判定树(即扩充二叉搜索树)描述有序顺序表的折半搜索,以及平均搜索长度(成功与不成功)的计算。4、二叉搜索树 动态搜索树与静态搜索树的特性 二叉搜索树的定义、二叉搜索树上的递归和非递归搜索算法 二叉搜索树搜索时的平均搜索长度(成功与不成功)的计算 二叉搜索树的插入与删除算法 AVL树结点上的平衡因子、AVL树的平衡旋转方法 高度为h的AVL树上的最少结点个数与最多结点个数 AVL树的搜索方法、插入与删除方法(不要求算法)三、教材中习题的解析7-1 设A = 1, 2, 3 , B = 3, 4, 5 ,求下列结果:(1) A + B(2) A * B(3) A - B(4) A.Contains (1)(5) A.AddMember (1)(6) A.DelMember (1)(7) A.Min ( )【解答】(1) 集合的并A + B = 1, 2, 3, 4, 5 (2) 集合的交A * B = 3 (3) 集合的差A - B = 1, 2 (4) 包含A.Contains (1) = 1,表示运算结果为True(5) 增加A.AddMember (1),集合中仍为 1, 2, 3 ,因为增加的是重复元素,所以不加入(6) 删除A.DelMember (1),集合中为 2, 3 (7) 求最小元素A.Min ( ),结果为17-2 试编写一个算法,打印一个有穷集合中的所有成员。要求使用集合抽象数据类型中的基本操作。如果集合中包含有子集合,各个子集合之间没有重复的元素,采用什么结构比较合适。【解答】集合抽象数据类型的部分内容template class Set /对象: 零个或多个成员的聚集。其中所有成员的类型是一致的, 但没有一个成员是相同的。 int Contains ( const Type x );/判元素x是否集合this的成员 int SubSet ( Set & right );/判集合this是否集合right的子集 int operator = ( Set & right );/判集合this与集合right是否相等 int Elemtype ( );/返回集合元素的类型 Type GetData ( ); /返回集合原子元素的值 char GetName ( ); /返回集合this的集合名 Set * GetSubSet ( );/返回集合this的子集合位置 Set * GetNext ( );/返回集合this的直接后继集合元素 int IsEmpty ( );/判断集合this空否。空则返回1, 否则返回0;ostream& operator ( ostream& out, Set t ) /友元函数, 将集合t输出到输出流对象out。 t.traverse ( out, t ); return out;void traverse ( ostream& out, Set s ) /友元函数, 集合的遍历算法 if ( s.IsEmpty ( ) = 0 ) /集合元素不空 if ( s.Elemtype ( ) = 0 ) out s.GetName ( ) ;/输出集合名及花括号 else if ( s.Elemtype ( ) = 1 ) /集合原子元素 out s.GetData ( );/输出原子元素的值 if ( s.GetNext ( ) != NULL ) out ,; else /子集合 traverse ( s. GetSubSet ( ) );/输出子集合 if ( s.GetNext ( ) != NULL ) out ,; traverse ( s.GetNext ( ) );/向同一集合下一元素搜索 else out ; 如果集合中包含有子集合,各个子集合之间没有重复的元素,采用广义表结构比较合适。也可以使用并查集结构。7-3 当全集合可以映射成1到N之间的整数时,可以用位数组来表示它的任一子集合。当全集合是下列集合时,应当建立什么样的映射?用映射对照表表示。(1) 整数0, 1, , 99(2) 从n到m的所有整数,n m(3) 整数n, n+2, n+4, , n+2k(4) 字母 a, b, c, , z(5) 两个字母组成的字符串, 其中, 每个字母取自 a, b, c, , z。【解答】(1) i i的映射关系,i = 0, 1, 2, , 99(2) i n-i 的映射关系,i = n, n+1, n+2, , m012m-nnn+1n+2m(3) i (i-n)/2 的映射关系,i = n, n+2, n+4, , n+2k012knn+2n+4n+2k(4) ord (c) ord (c) - ord (a) 的映射关系,c = a, b, c, , z01225abcz(5) (ord (c1) - ord (a) )*26 + ord (c2) - ord (a)的映射关系,c1 = c2 = a, b, c, , z012675aaabbazz7-4 试证明:集合A是集合B的子集的充分必要条件是集合A和集合B的交集是A。【证明】必要条件:因为集合A是集合B的子集,有A B,此时,对于任一x A,必有x B,因此可以推得x AB,就是说,如果A是B的子集,一定有AB = A。充分条件:如果集合A和集合B的交集AB是A,则对于任一x A,一定有x AB,因此可以推得x B,由此可得A B,即集合A 是集合B的子集。7-5 试证明:集合A是集合B的子集的充分必要条件是集合A和集合B的并集是B。【证明】必要条件:因为集合A是集合B的子集,有A B,此时,对于任一x A,必有x B, 它一定在AB中。另一方面,对于那些x A, 但x B的元素,它也必在AB中,因此可以得出结论:凡是属于集合B的元素一定在AB中,AB = B。充分条件:如果存在元素x A且x B,有x AB,但这不符合集合A和集合B的并集AB是B的要求。集合的并AB是集合B的要求表明,对于任一x AB,同时应有x B。对于那些满足x A的x,既然x AB,也应当x B,因此,在此种情况下集合A应是集合B的子集。7-6 设+、*、-是集合的或、与、差运算,试举一个例子,验证A + B = (A - B) + (B - A) + A * B【解答】若设集合A = 1, 3, 4, 7, 9, 15 ,集合B = 2, 3, 5, 6, 7, 12, 15, 17 。则A + B = 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 17 又A * B = 3, 7, 15 , A B = 1, 4, 9 , B A = 2, 5, 6, 12, 17 则 (A B) + (B A) + A * B = 1, 2, 3, 4, 5, 6, 7, 9, 12, 15, 17 有 A + B = (A B) + ( B A ) + A * B。 7-7 给定一个用无序链表表示的集合,需要在其上执行operator+( ), operator*( ), operator- ( ), Contains(x), AddMember (x), DelMember(x), Min( ),试写出它的类声明,并给出所有这些成员函数的实现。【解答】下面给出用无序链表表示集合时的类的声明。template class Set;/用以表示集合的无序链表的类的前视定义template class SetNode /集合的结点类定义friend class SetList;private: Type data;/每个成员的数据 SetNode *link;/链接指针public: SetNode (const Type& item ) : data (item), link (NULL);/构造函数;template class Set /集合的类定义private: SetNode *first, *last;/无序链表的表头指针, 表尾指针public: SetList ( ) first = last = new SetNode (0); /构造函数 SetList ( ) MakeEmpty ( ); delete first; /析构函数 void MakeEmpty ( );/置空集合 int AddMember ( const Type& x );/把新元素x加入到集合之中 int DelMember ( const Type& x );/把集合中成员x删去 Set & operator = ( Set & right );/复制集合right到this。 Set operator + ( Set & right );/求集合this与集合right的并 Set operator * ( Set & right );/求集合this与集合right的交 Set operator - ( Set & right );/求集合this与集合right的差 int Contains ( const Type& x );/判x是否集合的成员 int operator = ( Set & right );/判集合this与集合right相等 Type& Min ( );/返回集合中的最小元素的值(1) operator + ( )template Set Set : operator + ( Set & right ) /求集合this与集合right的并, 计算结果通过临时集合temp返回,this集合与right集合不变。 SetNode *pb = right.first-link;/right集合的链扫描指针 SetNode *pa, *pc;/this集合的链扫描指针和结果链的存放指针 Set temp; pa = first-link; pc = temp.first; while ( pa != NULL ) /首先把集合this的所有元素复制到结果链 pc-link = new SetNode ( pa-data ) ; pa = pa-link; pc = pc-link; while ( pb != NULL ) /将集合right中元素逐个拿出到this中查重 pa = first-link; while ( pa != NULL & pa-data != pb-data ) pa = pa-link; if ( pa = NULL )/在集合this中未出现, 链入到结果链 pc-link = new SetNode ( pa-data ); pc = pc-link; pb = pb-link; pc-link = NULL; last = pc;/链表收尾 return temp;(2) operator * ( )template Set Set : operator * ( Set & right ) /求集合this与集合right的交, 计算结果通过临时集合temp返回,this集合与right集合不变。 SetNode *pb = right.first-link;/right集合的链扫描指针 Set temp; SetNode *pc = temp.first;/结果链的存放指针 while ( pb != NULL ) /将集合right中元素逐个拿出到this中查重 SetNode *pa = first-link;/this集合的链扫描指针 while ( pa != NULL ) if ( pa-data = pb-data )/两集合公有的元素, 插入到结果链 pc-link = new SetNode ( pa-data ); pc = pc-link; pa = pa-link; pb = pb-link; pc-link = NULL; last = pc; /置链尾指针 return temp;(3) operator - ( ), template Set Set : operator - ( Set & right ) /求集合this与集合right的差, 计算结果通过临时集合temp返回,this集合与right集合不变。 SetNode *pa = first-link;/this集合的链扫描指针 Set temp; SetNode *pc = temp-first;/结果链的存放指针 while ( pa != NULL ) /将集合this中元素逐个拿出到right中查重 SetNode *pb = right.first-link;/right集合的链扫描指针 while ( pb != NULL & pa-data != pb-data ) pb = pb-link; if ( pb = NULL ) /此this中的元素在right中未找到, 插入 pc-link = new SetNode ( pa-data ); pc = pc-link; pa = pa-link; pc-link = NULL; last = pc;/链表收尾 return temp; (4) Contains(x)template int Set : Contains ( const Type& x ) /测试函数: 如果x是集合的成员, 则函数返回1, 否则返回0。 SetNode * temp = first-link;/链的扫描指针 while ( temp != NULL & temp-data != x ) temp = temp-link;/循链搜索 if ( temp != NULL ) return 1;/找到, 返回1 else return 0;/未找到, 返回0(5) AddMember (x) template int Set : AddMember ( const Type& x ) /把新元素x加入到集合之中。若集合中已有此元素, 则函数返回0, 否则函数返回1。 SetNode * temp = first-link;/ temp是扫描指针 while ( temp != NULL & temp-data != x ) temp = temp-link;/循链扫描 if ( temp != NULL ) return 0;/集合中已有此元素, 不加 last = last-link = new SetNode (x);/否则, 创建数据值为x的新结点, 链入 return 1;(6) DelMember (x) template int Set : DelMember ( const Type& x ) /把集合中成员x删去。若集合不空且元素x在集合中, 则函数返回1, 否则返回0。 SetNode * p = first-link, *q = first; while ( p != NULL ) if ( p-data = x ) /找到 q-link = p-link;/重新链接 if ( p = last ) last = q;/删去链尾结点时改链尾指针 delete p; return 1;/删除含x结点 else q = p; p = p-link; /循链扫描 return 0;/集合中无此元素(7) Min ( )template SetNode * Set : Min ( ) /在集合中寻找值最小的成员并返回它的位置。 SetNode * p = first-link, *q = first-link;/p是检测指针, q是记忆最小指针 while ( p != NULL ) if ( p-data data ) q = p;/找到更小的, 让q记忆它 p = p-link;/继续检测 return q;7-8 设有序顺序表中的元素依次为017, 094, 154, 170, 275, 503, 509, 512, 553, 612, 677, 765, 897, 908。试画出对其进行折半搜索时的二叉搜索树, 并计算搜索成功的平均搜索长度和搜索不成功的平均搜索长度。【解答】5091546770172755538970941705035126127659087-9 若对有n个元素的有序顺序表和无序顺序表进行顺序搜索, 试就下列三种情况分别讨论两者在等搜索概率时的平均搜索长度是否相同?(1) 搜索失败;(2) 搜索成功, 且表中只有一个关键码等于给定值k的对象;(3) 搜索成功, 且表中有若干个关键码等于给定值k的对象, 要求一次搜索找出所有对象。【解答】(1) 不同。因为有序顺序表搜索到其关键码比要查找值大的对象时就停止搜索,报告失败信息,不必搜索到表尾;而无序顺序表必须搜索到表尾才能断定搜索失败。(2) 相同。搜索到表中对象的关键码等于给定值时就停止搜索,报告成功信息。(3) 不同。有序顺序表中关键码相等的对象相继排列在一起,只要搜索到第一个就可以连续搜索到其它关键码相同的对象。而无序顺序表必须搜索全部表中对象才能确定相同关键码的对象都找了出来,所需时间就不相同了。前两问可做定量分析。第三问推导出的公式比较复杂,不再进一步讨论。7-10 假定用一个循环链表来实现一个有序表,并让指针head指向具有最小关键码的结点。指针current初始时等于head,每次搜索后指向当前检索的结点,但如果搜索不成功则current重置为head。试编写一个函数search(head, current, key)实现这种搜索。当搜索成功时函数返回被检索的结点位置,若搜索不成功则函数返回空指针0。请说明如何保持指针current以减少搜索时的平均搜索长度。【解答】current605040302010head相应的搜索函数可以定义为链表及链表结点类的友元函数,直接使用链表及链表结点类的私有数据成员。template ListNode * Search ( ListNode * head, ListNode *& current, Type key ) ListNode * p, * q; if ( key data link;/循链搜索其值等于key的结点 if ( p-data = key ) current = p; return p; /找到, 返回结点位置 else current = head; return NULL; /未找到, 返回空指针7-11 考虑用双向链表来实现一个有序表,使得能在这个表中进行正向和反向搜索。若指针p总是指向最后成功搜索到的结点,搜索可以从p指示的结点出发沿任一方向进行。试根据这种情况编写一个函数search(head, p, key),检索具有关键码key的结点,并相应地修改p。最后请给出搜索成功和搜索不成功时的平均搜索长度。p【解答】40706050302010headtemplate DblListNode * Search ( DblListNode * head, DblListNode *& p, Type key ) /在以head为表头的双向有序链表中搜索具有值key的结点。算法可视为双向链表类和双向链表/结点类的友元函数。若给定值key大于结点p中的数据, 从p向右正向搜索, 否则, 从p向左反/向搜索。 DblListNode * q = p; if ( key data ) while ( q != NULL & q-data key ) q = q- lLink; /反向搜索 else while ( q != NULL & q-data rLink; /正向搜索 if ( q != NULL & q-data = key ) p = q; return p; /搜索成功 else return NULL;如果指针p处于第i个结点(i = 1, 2, , n),它左边有i-1个结点,右边有n-i个结点。找到左边第i-1号结点比较2次,找到第i-2号结点比较3次,找到第1号结点比较i次,一般地,找到左边第k个结点比较i-k+1次(k = 1, 2, , i-1)。找到右边第i+1号结点比较2次,找到第i+2号结点比较3次,找到第n号结点比较n-i+1次,一般地,找到右边第k个结点比较k-i+1次(k = i+1, i+2, , n)。因此,当指针处于第i个结点时的搜索成功的平均数据比较次数为一般地,搜索成功的平均数据比较次数为如果指针p处于第i个结点(i = 1, 2, , n),它左边有i个不成功的位置,右边有n-i+1个不成功的位置。一般地,搜索不成功的平均数据比较次数为7-12 在一棵表示有序集S的二叉搜索树中,任意一条从根到叶结点的路径将S分为3部分:在该路径左边结点中的元素组成的集合S1;在该路径上的结点中的元素组成的集合S2;在该路径右边结点中的元素组成的集合S3。S = S1 S2 S3。若对于任意的a S1, b S2, c S3, 是否总有a b c?为什么?【解答】答案是否定的。举个反例:看下图粗线所示的路径153550657045 403025 S1 = 15 , S2 = 25, 30, 35, 45 , S3 = 40, 50, 65, 70 c = 40 S3,b = 45 S2,b c 不成立。7-13 请给出下列操作序列运算的结果:Union(1, 2), Union(3, 4), Union(3, 5), Union(1, 7), Union(3, 6), Union(8, 9), Union(1, 8), Union(3, 10), Union(3, 11), Union(3, 12), Union(3, 13), Union(14, 15), Union(16, 17), Union(14, 16), Union(1, 3), Union(1, 14),要求(1) 以任意方式执行Union;(2) 根据树的高度执行Union; (3) 根据树中结点个数执行Union。【解答】(1) 对于union(i, j),以i作为j的双亲1215310987016141311126547(2) 按i和j为根的树的高度实现union(i, j),高度大者为高度小者的双亲;81214310654916151311120(3) 按i和j为根的树的结点个数实现union(i, j),结点个数大者为结点个数小者的双亲。1401615187293456101113127-14 有n个结点的二叉搜索树具有多少种不同形态?【解答】 7-15 设有一个输入数据的序列是 46, 25, 78, 62, 12, 37, 70, 29 , 试画出从空树起,逐个输入各个数据而生成的二叉搜索树。【解答】464646464646782525782578257825加25加46空树加78371262126262加37加12加62464678257825126237126237加29加702970707-16 设有一个标识符序列else, public, return, template,p1=0.05, p2=0.2, p3=0.1, p4=0.05, q0=0.2, q1=0.1, q2=0.2, q3=0.05, q4=0.05,计算Wij、Cij和Rij,构造最优二叉搜索树。【解答】将标识符序列简化为 e, p, r, t ,并将各个搜索概率值化整,有eprtp1 = 1p2 = 4p3 = 2p4 = 1q0 = 4q1 = 2q2 = 4q3 = 1q4 = 1(1) 首先构造只有一个内结点的最优二叉搜索树:p1p2p4p3q4q3q3q2q2q0q1q1三个矩阵的内容如下:0123401234012340471518200072232390012221210131510102027102222479207122033313303304414040 Wij Cij Rij(2) 构造具有两个内结点的最优二叉搜索树C24 = 12T24 = 2C13 = 20T13 = 2C02 = 22T02 = 2p3p2p2q2p4p3p1q2q1q4q3q3q2q1q0(3) 构造具有三个内结点的最优二叉搜索树C03 = 32T03 = 2C14 = 27T14 = 2p2p2p1p3q1p3p4q2q3q2q1q0q4q3(4) 构造具有四个内结点的最优二叉搜索树 C04 = 39T04 = 2p2左子树 T01, 其 C01 = 7右子树 T24, 其 C24 = 12p1p3q2q1q0p4q4q37-17 在二叉搜索树上删除一个有两个子女的结点时,可以采用以下三种方法:(1) 用左子树TL上具有最大关键码的结点X顶替,再递归地删除X。 (2) 交替地用左子树TL上具有最大关键码的结点和右子树TR上具有最小关键码的结点顶替,再递归地删除适当的结点。(3) 用左子树TL上具有最大关键码的结点或者用右子树TR上具有最小关键码的结点顶替,再递归地删除适当的结点。可随机选择其中一个方案。试编写程序实现这三个删除方法,并用实例说明哪一个方法最易于达到平衡化。【解答】 在被删结点有两个子女时用左子树TL中具最大关键码的结点顶替的算法:template BstNode * BST : leftReplace ( BstNode * ptr ) BstNode * temp = ptr-leftChild;/进到ptr的左子树 while ( temp-rightChild != NULL ) temp = temp-rightChild;/搜寻中序下最后一个结点 ptr-data = temp-data;/用该结点数据代替根结点数据 return temp; 在被删结点有两个子女时用右子树TR中具最小关键码的结点顶替的算法: template BstNode * BST : rightReplace ( BstNode * ptr ) BstNode * temp = ptr-rightChild;/进到ptr的右子树 while ( temp-leftChild != NULL ) temp = temp-leftChild;/搜寻中序下最后一个结点 ptr-data = temp-data;/用该结点数据代替根结点数据 return temp; (1) 用左子树TL上具有最大关键码的结点X顶替,再递归地删除X。template void BST : Remove ( Type& x, BstNode *& ptr ) /私有函数:在以ptr为根的二叉搜索树中删除含x的结点。若删除成功则新根通过ptr返回。 BstNode * temp; if ( ptr != NULL )if ( x data ) Remove ( x, ptr-leftChild );/在左子树中执行删除else if ( x ptr-data ) Remove ( x, ptr-rightChild );/在右子树中执行删除 else if ( ptr-leftChild != NULL & ptr-rightChild != NULL ) / ptr指示关键码为x的结点,它有两个子女temp = leftReplace ( ptr );/在ptr的左子树中搜寻中序下最后一个结点顶替x Remove ( ptr-data, ptr-rightChild );/在ptr的右子树中删除该结点 else / ptr指示关键码为x的结点,它只有一个或零个子女 temp = ptr; if ( ptr-leftChild = NULL ) ptr = ptr-rightChild;/只有右子女 else if ( ptr-rightChild = NULL ) ptr = ptr-leftChild;/只有左子女 delete temp; (2) 交替地用左子树TL上具有最大关键码的结点和右子树TR上具有最小关键码的结点顶替,再递归地删除适当的结点。template void BST : Remove ( Type& x, BstNode *& ptr, int& dir ) /私有函数:在以ptr为根的二叉搜索树中删除含x的结点。若删除成功则新根通过ptr返回。在/参数表中有一个引用变量dir, 作为调整方向的标记。若dir = 0, 用左子树上具有最大关键码的/结点顶替被删关键码; 若dir = 1, 用右子树上具有最小关键码的结点顶替被删关键码结点, 在调/用它的程序中设定它的初始值为0。 BstNode * temp; if ( ptr != NULL )if ( x data ) Remove ( x, ptr-leftChild, dir );/在左子树中执行删除else if ( x ptr-data ) Remove ( x, ptr-rightChild, dir );/在右子树中执行删除 else if ( ptr-leftChild != NULL & ptr-rightChild != NULL ) / ptr指示关键码为x的结点,它有两个子女if ( dir = 0 ) temp = leftReplace ( ptr ); dir = 1;/在ptr的左子树中搜寻中序下最后一个结点顶替x Remove ( ptr-data, ptr-rightChild, dir );/在ptr的右子树中删除该结点 else temp = rightReplace ( ptr ); dir = 0;/在ptr的右子树中搜寻中序下第一个结点顶替x Remove ( ptr-data, ptr-leftChild, dir );/在ptr的左子树中删除该结点 else / ptr指示关键码为x的结点,它只有一个或零个子女 temp = ptr; if ( ptr-leftChild = NULL ) ptr = ptr-rightChild;/只有右子女 else if ( ptr-rightChild = NULL ) ptr = ptr-leftChild;/只有左子女 delete temp; (3) 用左子树TL上具有最大关键码的结点或者用右子树TR上具有最小关键码的结点顶替,再递归地删除适当的结点。可随机选择其中一个方案。#include template void BST : Remove ( Type& x, BstNode *& ptr ) /私有函数:在以ptr为根的二叉搜索树中删除含x的结点。若删除成功则新根通过ptr返回。在/程序中用到一个随机数发生器rand( ), 产生032767之间的随机数, 将它除以16384, 得到02/之间的浮点数。若其大于1, 用左子树上具有最大关键码的结点顶替被删关键码; 若其小于或等/于1, 用右子树上具有最小关键码的结点顶替被删关键码结点, 在调用它的程序中设定它的初始/值为0。 BstNode * temp; if ( ptr != NULL )if ( x data ) Remove ( x, ptr-leftChild );/在左子树中执行删除else if ( x ptr-data ) Remove ( x, ptr-rightChild );/在右子树中执行删除 else if ( ptr-leftChild != NULL & ptr-rightChild != NULL ) / ptr指示关键码为x的结点,它有两个子女if ( (float) ( rand ( ) / 16384 ) 1 ) temp = leftReplace ( ptr ); /在ptr的左子树中搜寻中序下最后一个结点顶替x Remove ( ptr-data, ptr-rightChild );/在ptr的右子树中删除该结点 else temp = rightReplace ( ptr ); /在ptr的右子树中搜寻中序下第一个结点顶替x Remove ( ptr-data, ptr-leftChild );/在ptr的左子树中删除该结点 else / ptr指示关键码为x的结点,它只有一个或零个子女 temp = ptr; if ( ptr-leftChild = NULL ) ptr = ptr-rightChild;/只有右子女 else if ( ptr-rightChild = NULL ) ptr = ptr-leftChild;/只有左子女 delete temp; 7-18 (1) 设T是具有n个内结点的扩充二叉搜索树, I是它的内路径长度, E是它的外路径长度。试利用归纳法证明 E = I + 2n, n 1。(2) 利用(1)的结果, 试说明: 成功搜索的平均搜索长度Sn与不成功搜索的平均搜索长度Un之间的关系可用公式 Sn = ( 1 + 1/n ) Un - 1, n 1 表示。【解答】(1) 用数学归纳法证明。当n = 1时,有1个内结点(I = 0),2个外结点(E = 2),满足E = I+2n。设n = k 时结论成立,Ek = Ik + 2k。则当n = k + 1时,将增加一个层次为l的内结点,代替一个层次为l的外结点,同时在第l+1层增加2个外结点,则Ek+1 = Ek l + 2*(l+1) = Ek + l +2,Ik+1 = Ik + l,将Ek = Ik + 2k代入,有Ek+1 = Ek + l +2 = Ik + 2k + l +2 = Ik+1+ 2(k +1),结论得证。(2) 因为搜索成功的平均搜索长度Sn与搜索不成功的平均搜索长度Un分别为其中,ci是各内结点所处层次,cj是各外结点所处层次。因此有 (n+1)Un = En = In + 2n = nSn n +2n = nSn +n7-19 求最
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 大学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!