二叉搜索树——算法导论(14)

1. 什么是二叉搜索树

    顾名思义,二叉搜索树是以一棵二叉搜索树来组织的。如下图,这样的一棵树可以使用一个链表数据结构来表示,其中的每一个节点是一个对象。除了key和卫星数据之外,每个节点还包含属性left(左孩子)、right(右孩子)、和p(双亲)(若不存在,则值为NIL)。

    二叉搜索树中的关键字总是以满足二叉搜索树性质的方式存储:

设x是二叉搜索树的一个节点。如果y是x左子树中的一个节点,那么y.key≤x.key。如果y是x右子树中的一个节点,那么y.key≥x.key。

    二叉搜索树性质允许我们使用一种简单的地鬼算法来按一定的顺序输出二叉搜索树中的所有关键字。我们常用的有先序遍历(输出的子树根的关键字位置位于左子树关键字和右子树关键字之间)、中序遍历后序遍历

下面给出先序遍历的递归算法:

    我们可以证明:遍历一棵有n个节点的二叉搜索树需要花费θ(n)的时间(证明略)。

2. 查询二叉搜索树

(1)

    这一小节,我们来讨论二叉搜索树的诸如:SEARCH,MINIMUM,MAXIMUN,SUCCESSOR,PERDECESSOR操作。

(2) search

    我们使用如下一种算法去查询一棵二叉搜索树。该方法要求输入一个指向根节点的指针x和待查找的关键字k;输出为指向关键字为k的节点的指针(若存在。否则输出NIL)。

我们很容易知道,该查询算法的时间为O(h),其中h为树的高度。

更好地,我们可以用如下迭代来替代递归,因为递归可能会造成栈内存溢出,在大多数计算机上,迭代版本的效率要更高。

(3) minimum和maximum

    由于二叉搜索树性质的存在,我们可以很容易的找出树中的最大和最小关键字元素。

同样,上面的两种方法均可以在O(h)时间内完成。

(4) successor和predecessor

    给定一棵二叉搜索树的某个节点,有时我们需要按中序遍历的次序去查找该节点的前驱和后驱。如在下图中,我们容易看出,key为4的节点的前驱是key为3的节点,后驱是key为6的节点;key为7的节点的前驱是key为6的节点,后驱是key为9的节点。

下面是求某节点后驱的算法:

解释一下上面求后驱的过程。我们分两种情况讨论:

① 如果x的右子树不为NIL,那么x的后继即为右子树中key最小的元素。

② 如果x的右子树为NIL,那么x的后继节点必将在其祖先节点(包括父节点)中产生。并且该祖先节点必须是从下至上,第一次满足自己为自己父节点的右节点。

同理,我们可以求出x的前驱节点,这里就不给出算法了。

很容易看出,它们所需的时间均为O(h)。

    由此,我们得出:在一棵高度为h的二叉搜索树上,集合操作SEARCH,MINIMUM,MAXIMUN,SUCCESSOR,PERDECESSOR都可以在O(h)时间内完成。

3. 插入和删除

(1) 插入

    相比删除操作,插入操作相对简单一些。下面给出insert算法。该算法的作用是,将一个新节点z插入到一棵二叉搜索树T中。

算法很简单,这里就不做说明了。

同样可以看出,插入操作的时间为O(h)。

(2) 删除

    我们按照被删除的节点的子节点个数,分以下三种情况来讨论:

① 被删除节点没有孩子。只需要修改其父节点,用NIL去替换自己。

② 被删除节点有一个孩子。也只需要修改其父节点,用这个孩子去替换自己。

③ 被删除节点有两个孩子。那么先找z的后继y(一定在z的右子树中),并让y占据树中z的位置。z的原来的右子树部分称为y的新的右子树,并且z的左子树成为y的左子树。

    前两种情况比较简单,至于第三种情况,我们还可以细分:

① 如果z的后继y就是z的右孩子(即y没有左孩子),直接用y代替z,并保留y的右子树,如下图所示:

② 如果z的后继y不是z的右孩子,先用y的右孩子替换y,再用y替换z。如下图所示:

    为了实现上面的过程,我们先来实现transplant过程。该过程能够实现让子树v代替子树μ。实现算法如下:

    利用transplant,我们根据上述的讨论来实现删除操作:

注意到上述删除操作过程并没有给出我们上述讨论中,情况①中z没有孩子的情况。事实上,上述讨论中情况①已经被包含在情况②中,即z没有孩子的情况等价于z有一个key为NIL的左孩子或有一个key为NIL的右孩子。

    分析该算法,我们发现除了transplant外,其他操作均花费常量时间。因此删除操作将花费O(h)时间。

    综合以上的所有分析,我们可知:二叉搜索树上的每个基本操作都可以在O(h)时间内完成(其中h为树的高度)。

4. 随机构建二叉搜索树

    我们先给出随机构建二叉搜索树的定义:向一棵空树随机的插入n个关键字而得到的树。这里随机的意思是n个关键字的n!种排列都等可能的出现。

    我们要证明如下定理:

一棵有n个不同关键字的随机构建二叉搜索树的期望高度为O(lgn)。

    先定义三个随机变量Xn,Yn,Rn,其中,Xn表示一棵有n个不同关键字的随机构建二叉搜索树的高度;Yn=2^Xn表示二叉搜索树的指数高度(exponential height)。Rn表示当在n个不同的关键字中选择一个作为树根时,该关键字在这n个关键字集合中的秩(rank)(即Rn表示这些关键字排好序后这个关键字应占据的位置)。这样如果Rn = i,那么表示根的左子树有i-1个元素,右子树有n-i个元素,此时有:

Yn = 2 · max(Yi-1, Yn-i)

    我们再定义一个指示器随机变量Zn,i,Zn,i = I{Rn = i}。因为Rn对于集合{1,2,…,n}中的任一元素都是等可能的,因此有:

p{Rn = i} = 1 / n,(i=1,2,…,n)

E(Zn,i) = 1 / n

由于Zn,i只等于1或0,Yn = 2 · max(Yi-1, Yn-i) = 

于是有:

在上式最后的和式中,Y[0],Y[1],…,Y[n-1]都会出现两次(E[Yi-1]和E[Yn-i]都会出现),因此:

上式是一个递归式,我们可以猜测 ,并用数学归纳法可证明(这里略)。

有Jensen不等式,我们可得进一步可得

于是,

两边去对数,最终得:

时间: 2024-08-24 19:44:33

二叉搜索树——算法导论(14)的相关文章

【算法导论】学习笔记——第12章 二叉搜索树

搜索树数据结构支持多种动态集合操作,包括SEARCH.MINIMUM.MAXIMUM.PREDECESSOR.SUCCESSOR.INSRT和DELETE操作等.基本的搜索树就是一棵二叉搜索树.12.1 什么是二叉搜索树1. 二叉搜索树的性质:设x是二叉搜索树中的一个结点.如果y是x左子树中的一个结点,那么y.key<=x.key.如果y是x右子树中的一个结点,那么y.key>=x.key.三种遍历时间复杂度是O(n),这是显然的. 12.1-3 1 void Inorder_Tree_Wal

算法导论第十二章 二叉搜索树

一.二叉搜索树概览 二叉搜索树(又名二叉查找树.二叉排序树)是一种可提供良好搜寻效率的树形结构,支持动态集合操作,所谓动态集合操作,就是Search.Maximum.Minimum.Insert.Delete等操作,二叉搜索树可以保证这些操作在对数时间内完成.当然,在最坏情况下,即所有节点形成一种链式树结构,则需要O(n)时间.这就说明,针对这些动态集合操作,二叉搜索树还有改进的空间,即确保最坏情况下所有操作在对数时间内完成.这样的改进结构有AVL(Adelson-Velskii-Landis)

算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树

搜索树数据结构支持许多动态集合操作,如search(查找).minmum(最小元素).maxmum(最大元素).predecessor(前驱).successor(后继).insert(插入).delete(删除),这些都是基本操作,可以使用一颗搜索树当做一个字典或者一个优先队列. 12.1.什么事二叉搜索树 二叉搜索树是以一棵二叉树来组织的,可以用一个链表数据结构来表示,也叫二叉排序树.二叉查找树: 其中的每个结点都是一个对象,每个对象含有多个属性(key:该结点代表的值大小,卫星数据:不清楚

【算法导论】二叉搜索树

什么是二叉搜索树 顾名思义,一棵二叉搜索树是以一棵二叉树来组织的.这样一棵树可以使用一个链表数据结构来表示,其中每个结点就是一个对象.除了key和卫星数据之外,每个结点还包含属性left.right和p,它们分别指向结点的左孩子.右孩子和双亲.如果某个孩子结点和父结点不存在,则相应属性的值为NIL.根结点是树中唯一父指针为NIL的结点. 二叉搜索树中的关键字总是以满足二叉搜索树性质的方式来存储: 设x是二叉搜索树中的一个结点.如果y是x左子树中的一个结点,那么 y.key <= x.key.如果

算法导论Part3: 二叉搜索树

1.概念 二叉搜索树性质:设x是二叉搜索树的一个节点,那么: a) 对x左子树中任意节点y, y.key < x.key b) 对x右子树种任意节点y, y.key >= x.key 2.数据结构 1 struct TreeNode 2 { 3 TreeNode(int key): left(NULL), right(NULL), parent(NULL), key(key) {}; 4 TreeNode* left; 5 TreeNode* right; 6 TreeNode* parent

【算法导论学习-24】二叉树专题2:二叉搜索树(Binary Search Tree,BST)

一.   二叉搜索树(Binary SearchTree,BST) 对应<算法导论>第12章.相比一般二叉树,BST满足唯一的条件:任意节点的key>左孩子的key,同时<右孩子的key. 1.     节点类: public class BinarySearchTreesNode<T> { private int key; private T satelliteData; private BinarySearchTreesNode<T> parent, l

【算法导论】动态规划之“最优二叉搜索树”

之前两篇分别讲了动态规划的"钢管切割"和"矩阵链乘法",感觉到了这一篇,也可以算是收官之作了.其实根据前两篇,到这里,也可以进行一些总结的,我们可以找到一些规律性的东西. 所谓动态规划,其实就是解决递归调用中,可能出现重复计算子问题,从而导致耗费大量时间,去做重复劳动的问题.解决思路就是,将重复做过的子问题的结果,先存起来,等之后再需要用到的时候,直接拿过来用,而不需要再去计算. 但是这里还需要注意一些地方: ①要解决的问题,比如"钢管切割"中的

算法导论:二叉搜索树

定义: (0)二叉树 (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3)左.右子树也分别为二叉排序树 数据结构定义 public class TreeNode { public int val; public TreeNode left; public TreeNode right; public TreeNode(int val){ this.val = val; this.left = left=null

算法导论 第三部分——基本数据结构——二叉搜索树

一.什么是二叉搜索树 二叉查找树是按照二叉树结构来组织的,因此可以用二叉链表结构表示.二叉查找树中的关键字的存储方式满足的特征是:设x为二叉查找树中的一个结点.如果y是x的左子树中的一个结点,则key[y]≤key[x].如果y是x的右子树中的一个结点,则key[x]≤key[y].根据二叉查找树的特征可知,采用中根遍历一棵二叉查找树,可以得到树中关键字有小到大的序列. 二叉树的查找.最大/小.前驱和后继的伪代码: 复杂度都是 h //search 递归版 TREE_SEARCH(x,k) if