1、1 1二叉搜索树二叉搜索树 (Binary Search Tree)(Binary Search Tree)n定义定义 二叉搜索树或者是一棵空树,或者是具二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:有下列性质的二叉树:每个结点都有一个作为搜索依据的关键每个结点都有一个作为搜索依据的关键码码(key),所有结点的关键码互不相同。,所有结点的关键码互不相同。左子树(如果非空)上所有结点的关键左子树(如果非空)上所有结点的关键码都小于根结点的关键码。码都小于根结点的关键码。右子树(如果非空)上所有结点的关键右子树(如果非空)上所有结点的关键码都大于根结点的关键码。码都大于根结点的关键码。左
2、子树和右子树也是二叉搜索树。左子树和右子树也是二叉搜索树。2 2351545504025102030二叉搜索树例二叉搜索树例n结点左子树上所结点左子树上所有关键码小于结有关键码小于结点关键码;点关键码;n右子树上所有关右子树上所有关键码大于结点关键码大于结点关键码;键码;n注意:若从根结点到某个叶结点有一条路径,注意:若从根结点到某个叶结点有一条路径,路径左边的结点的关键码不一定小于路径上路径左边的结点的关键码不一定小于路径上的结点的关键码。如箭头所示路径。的结点的关键码。如箭头所示路径。3 3n性质性质:如果对一棵二叉搜索树进行中序如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各
3、结遍历,可以按从小到大的顺序,将各结点关键码排列起来,所以也称二叉搜索点关键码排列起来,所以也称二叉搜索树为树为二叉排序树二叉排序树(BST)。n二叉搜索树的类定义二叉搜索树的类定义 略略n二叉搜索树的类定义用二叉链表作为它二叉搜索树的类定义用二叉链表作为它的存储表示,许多操作的实现与二叉树的存储表示,许多操作的实现与二叉树类似。类似。4 4二叉搜索树的搜索算法二叉搜索树的搜索算法n在二叉搜索树上进行搜索,是一个在二叉搜索树上进行搜索,是一个从根结点开从根结点开始始,沿某一个分支逐层向下沿某一个分支逐层向下进行比较判等的过进行比较判等的过程。它可以是一个递归的过程。程。它可以是一个递归的过程。
4、n假设想要在二叉搜索树中搜索关键码为假设想要在二叉搜索树中搜索关键码为 x 的元的元素,搜索过程从根结点开始。素,搜索过程从根结点开始。n如果如果根指针为根指针为NULL,则,则搜索不成功搜索不成功;否则用;否则用给定值给定值 x 与根结点的关键码进行比较:与根结点的关键码进行比较:若若给定值等于根结点关键码给定值等于根结点关键码,则,则搜索成功搜索成功,返回搜索成功信息并报告搜索到结点地址。返回搜索成功信息并报告搜索到结点地址。5 5 若给定值小于根结点的关键码,则继续若给定值小于根结点的关键码,则继续递归搜索根结点的左子树;递归搜索根结点的左子树;否则。递归搜索根结点的右子树。否则。递归搜
5、索根结点的右子树。搜索搜索45搜索成功搜索成功搜索搜索28搜索失败搜索失败3515455040251020306 6BSTNode*Search(T x,BSTNode*subtree)/递归算法:在以 subtree 为根的二叉搜索树中/搜索含 x 的结点。若找到,则函数返回该结点/的地址,否则函数返回 NULL 值。if(subtree=NULL)return NULL;else if(x data)return Search(x,subtree-left);else if(x subtree-data)return Search(x,subtree-right);else return
6、subtree;/搜索成功7 7BSTNode*Search(T x,BSTNode*subtree)/迭代算法:在当前以 subtree 为根的二叉搜索/树中搜索含 x 的结点。若找到,则函数返回该/结点的地址,否则函数返回 NULL 值。while(subtree!=NULL)if(x=subtree-data)return subtree;if(x data)subtree=subtree-left;else subtree=subtree-right;return NULL;8 8n搜索过程是从根结点开始,沿某条路径自上而搜索过程是从根结点开始,沿某条路径自上而下逐层比较判等的过程。下
7、逐层比较判等的过程。n搜索成功,搜索指针将停留在树上某个结点;搜索成功,搜索指针将停留在树上某个结点;搜索不成功,搜索指针将走到树上某个结点的搜索不成功,搜索指针将走到树上某个结点的空子树。空子树。n设树的高度为设树的高度为 h,最多比较次数不超过,最多比较次数不超过 h。9 9二叉搜索树的插入算法二叉搜索树的插入算法n为了向二叉搜索树中插入一个新元素,必须为了向二叉搜索树中插入一个新元素,必须先检查这个元素是否在树中已经存在先检查这个元素是否在树中已经存在。n在插入之前,先使用搜索算法在树中检查要在插入之前,先使用搜索算法在树中检查要插入的元素在不在树中。插入的元素在不在树中。如果搜索成功,
8、说明树中已经有这个元素,如果搜索成功,说明树中已经有这个元素,不再插入;不再插入;如果搜索不成功,说明树中原来没有关键如果搜索不成功,说明树中原来没有关键码等于给定值的结点,把新元素加到搜索码等于给定值的结点,把新元素加到搜索操作停止的地方。操作停止的地方。1010插入新结点插入新结点 28二叉搜索树的插入二叉搜索树的插入n每次结点的插入,都要每次结点的插入,都要从根结点出发搜索插入从根结点出发搜索插入位置,然后把新结点作位置,然后把新结点作为叶结点插入。为叶结点插入。3515455040251020302811 11二叉搜索树的插入算法二叉搜索树的插入算法bool Insert(T e,BS
9、TNode&subtree)/递归算法:在以 subtree 为根的二叉搜索树中插入/值为 e 的结点。若树中已有结点 e,则不插入 if(subtree=NULL)/新结点作为叶结点插入 subtree=new BSTNode(e);/创建新结点 return true;else if(e data)Insert(e,subtree-left);else if(e subtree-data)Insert(e,subtree-right);1212n注意参数表中引用型指针参数注意参数表中引用型指针参数subtree的的使用。使用。n利用二叉搜索树的插入算法,可以很方利用二叉搜索树的插入算法,可
10、以很方便地建立二叉搜索树。便地建立二叉搜索树。1313输入数据输入数据 53,78,65,17,87,09,81,15 5353785378655378651753786587175378650917875378658117870953786515178709811414void createBST(T EndValue)/从键盘上输入元素序列,建立一棵二叉搜索树,/参数 EndValue 表示序列的结束符 root=NULL;/root 为树根,初始化为空树cin x;/输入数据 while(x.key!=EndValue)/RefValue是一个输入结束标志 Insert(x,root);
11、cin x;/插入,再输入数据 1515二叉搜索树的删除算法二叉搜索树的删除算法n在二叉搜索树中删除一个结点时,必须将因在二叉搜索树中删除一个结点时,必须将因删除结点而断开的二叉链表重新链接起来,删除结点而断开的二叉链表重新链接起来,同时确保二叉搜索树的性质不会失去。同时确保二叉搜索树的性质不会失去。n为保证在删除后树的搜索性能不至于降低,为保证在删除后树的搜索性能不至于降低,还需要防止重新链接后树的高度增加。还需要防止重新链接后树的高度增加。删除叶结点删除叶结点,只需将其双亲结点指向它的,只需将其双亲结点指向它的指针清零,再释放它即可。指针清零,再释放它即可。被删结点右子树为空被删结点右子树
12、为空,可以拿它的左子女,可以拿它的左子女结点顶替它的位置,再释放它。结点顶替它的位置,再释放它。1616被删结点左子树为空被删结点左子树为空,可以拿它的右子女结,可以拿它的右子女结点点顶替它的位置,再释放它。顶替它的位置,再释放它。被删结点左、右子树都不为空被删结点左、右子树都不为空,可以在它的,可以在它的右子树中寻找中序下的第一个结点右子树中寻找中序下的第一个结点(关键码关键码最小最小),),用它的值填补到被删结点中,再来处用它的值填补到被删结点中,再来处理这个结点的删除问题。理这个结点的删除问题。5378651787092345删除45右子树空,用左子女顶替5378651787092317
13、178853788817940923删除78左子树空,用右子女顶替53948817092353788117940945删除78在右子树上找中序下第一个结点填补23655381881794094523651818二叉搜索树的删除算法二叉搜索树的删除算法bool Remove(x,BSTNode&subtree)/递归算法:在以 subtree 为根的二叉搜索树中/删除含 x 的结点if(subtree=NULL)return false;if(x data)/在左子树中执行删除return Remove(x,subtree-left);else if(x subtree-data)/在右子树中执
14、行删除 return Remove(x,subtree-right);else /找到了被删结点1919/1.左、右子女均不空if(subtree-left!=NULL&subtree-right!=NULL)/subtree指示关键码为x的结点,它有两个子女 temp=subtree-right;/到右子树搜寻中序下第一个结点 while(temp-left!=NULL)temp=temp-left;subtree-data=temp-data;/用该结点数据代替根结点数据 Remove(temp-data,subtree-right);2020else /subtree指示的结点最多有一个
15、子女 temp=subtree;if(subtree-left=NULL)subtree=subtree-right;else subtree=subtree-left;delete temp;return true;n注意在删除算法参数表引用型指针参数的使用。注意在删除算法参数表引用型指针参数的使用。2121 二叉搜索树性能分析二叉搜索树性能分析n对于有对于有 n 个关键码的集合,其关键码有个关键码的集合,其关键码有 n!种种不同排列,可构成不同二叉搜索树有不同排列,可构成不同二叉搜索树有 (棵棵)Cnnn2112,1,3 1,2,3 1,3,2 2,3,1 3,1,2 3,2,112311
16、11322233232222n同样同样 3 个数据个数据 1,2,3,输入顺序不同,建立,输入顺序不同,建立起来的二叉搜索树的形态也不同。这直接影响起来的二叉搜索树的形态也不同。这直接影响到二叉搜索树的搜索性能。到二叉搜索树的搜索性能。n如果输入序列选得不好,会建立起一棵单支树,如果输入序列选得不好,会建立起一棵单支树,使得二叉搜索树的高度达到最大。使得二叉搜索树的高度达到最大。n用树的搜索效率来评价这些二叉搜索树。用树的搜索效率来评价这些二叉搜索树。n为此,在二叉搜索树中加入外结点,形成判定为此,在二叉搜索树中加入外结点,形成判定树。外结点表示失败结点,内结点表示搜索树树。外结点表示失败结点
17、,内结点表示搜索树中已有的数据。中已有的数据。n这样的判定树即为这样的判定树即为扩充的二叉搜索树扩充的二叉搜索树。2323n举例说明。已知关键码集合举例说明。已知关键码集合 a1,a2,a3=do,if,to,对应搜索概率,对应搜索概率p1,p2,p3,在各搜索不成功在各搜索不成功间隔内搜索概率分别为间隔内搜索概率分别为q0,q1,q2,q3。可能的二。可能的二叉搜索树如下所示。叉搜索树如下所示。doiftodoiftoq0q1p1q2p2q3p3q0q1q2q3p1p2p3(a)(b)2424判定树判定树doiftoq0q1p1q2p2q3p3doiftoq0q1p1q2p2q3p3(d)(
18、c)doiftoq0q1p1q2p2q3p3(e)2525.*i lipASLnisucc1n在判定树中在判定树中u 表示表示内部结点内部结点,包含了关键码集合中的,包含了关键码集合中的某一个关键码;某一个关键码;u 表示表示外部结点外部结点,代表各关键码间隔中的,代表各关键码间隔中的不在关键码集合中的关键码。不在关键码集合中的关键码。n在每两个外部结点间必存在一个内部结点在每两个外部结点间必存在一个内部结点。n一棵判定树上的搜索成功的平均搜索长度一棵判定树上的搜索成功的平均搜索长度ASLsucc可以定义为该树所有内部结点上的搜可以定义为该树所有内部结点上的搜索概率索概率pi与搜索该结点时所需
19、的关键码比较与搜索该结点时所需的关键码比较次数次数ci(=li,即结点所在层次即结点所在层次)乘积之和:乘积之和:2626n设各关键码的搜索概率相等:设各关键码的搜索概率相等:pi=1/nn搜索不成功的平均搜索长度搜索不成功的平均搜索长度ASLunsucc为树中所为树中所有外部结点上搜索概率有外部结点上搜索概率qj与到达外部结点所与到达外部结点所需关键码比较次数需关键码比较次数cj(=lj)乘积之和:乘积之和:n设外部结点搜索概率相等:设外部结点搜索概率相等:qj=1/(n+1):.nisucci lnASL11njunsuccjljqASL0).1 (*njunsuccjlnASL0(11).1