二叉排序树
二叉排序树: 或者是一棵空树;或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也分别为二叉排序树。
二叉排序树插入
查询
二叉排序树又称二叉查找树,根据上述定义的结构特点可见。即当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。
Status SearchBST(BiTree T,KeyType key,BiTree f,BiTree &p){
//在根指针T所指二叉排序树中递归地查找其关键字等于key的数据元素,若查找成功
//则指针p指向该数据元素结点,并返回TRUE,否则指针p指向查找路径上访问的
//最后一个结点并返回FALSE,指针f指向T的双亲,其初始调用值为NULL
if(!T){//查找不成功
p = f;
return FALSE;
}
else if EQ(key, T->data.key){//查找成功
p = T;
return TRUE;
}
else if LT(key, T->data.key)//在左子树中继续查找
return SearchBST(T->lchild, key, T, p);
else //在右子树中继续查找
return SearchBST(T->rchild, key, T, p);
}
查找分析
6 个记录的查找概率相等=1/6
(a)树平均查找长度:ASL(a) = (1+2+2+3+3+3)/6 = 14/6
(b)树平均查找长度:ASL(b) = (1+2+3+4+5+6)/6 = 21/6
所以含有 n 个结点的二叉排序树的平均平均查找长度和树的形态有关。
最差情况:二叉树排序树为单只树,平均查找长度与顺序查找相同 (n+1)/2
最好情况:与折半查找的判断树相同,平均查找长度与 log2n 成正比
P(n) ≤ 2(1+1/n)ln n
插入
树的结构不是一次生成的,而是在查找过程中,在树中不存在关键字等于给定值的结点时再进行插入。新插入的结点一定是一个新添加的叶子结点,并且是查找不成功是查找路径上访问的最后一个一节点的左孩子或右孩子。
Status InsertBST(BiTree &T, ElemType e){
//当二叉排序树T中不存在关键字等于e.key的数据元素时,插入e并返回TRUE
//否则返回FALSE
if(!SearchBST(T, e.key, NULL, p)){//查找不成功
s = (BiTree)malloc(sizeof(BiTNode));
s->data = e; s->lchild = s->rchild = NULL;
if(!p)//被插结点*s为新的根结点
T = s;
else if LT(e.key, p->data.key)//被插结点*s为左孩子
p->lchild = s;
else//被插结点*s为右孩子
p->rchild = s;
return TRUE;
}
}
建立
从空树出发,经历一系列的查找插入操作之后,可生成一棵二叉树。
设查找序列为{45,24,53,45,12,24,90},生成二叉排序树过程如下:
可以看出,中序遍历二叉排序树可得到一个关键字的有序序列。
二叉排序树删除
对于二叉排序树,删去树上一个结点相当于删去有序序列中的一个记录,只要在删除某个结点之后依旧保持二叉排序树的特殊即可。
假设在二叉排序树上被删结点为 *p(指向结点的指针为 p),其双亲结点为 *f(结点指针为 f),且不失一般性,可设 *p 是 *f 的左孩子。
下面分 3 种情况进行讨论:
(1) 若 *p 结点为叶子结点,即 PL 和 PR 均为空树。由于删去叶子结点不破坏整棵树的结构,则只需修改其双亲结点的指针即可。
(2) 若 *p 结点只有左子树 PL 或者只有右子树 PR,此时只要令 PL 或 PR 直接成为其双亲结点 *f 的左子树即可。显然,作此修改也不破坏二叉排序树的特性。
(3) 若 *p 结点的左子树和右子树均不空。显然,此时不能如上简单处理。从下图中(b)可知,在删去 *p 结点之前,中序遍历该二叉树得到的序列为{…CLC…QLQSLSPPRF…},在删去 *p 之后,为保存其他元素之间的相对位置不变,可以有两种做法:其一是令 *p 的左子树为 *f 的左子树,而 *p 的右子树为 *s 的右子树,如下图©;其二是令 *p 的直接前驱(或直接后继)替代 *p,然后再从二叉排序树中删去它的直接前驱(或直接后继)。如下图(d)所示,当以直接前驱 *s 替代 *p 时,由于 *s 只要左子树 SL,则在删去 *s 之后,只要令 SL 为 *s 的双亲 *q 的右子树即可。
Status DeleteBST(BiTree &T, KeyType key){
//若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素结点
//并返回TRUE;否则返回FALSE
if(!T)//不存在关键字等于key的数据元素
return FALSE;
else{
if(EQ(key, T->data.key))//找到关键字等于key的数据元素
return Delete(T);
else if(LT(key, T->data.key))
return Delete(T->lchild, key);
else
return Delete(T->rchild, key);
}
}
Status Delete(BiTree &p){
//从二叉排序树中删除结点p,并重接它的左或右子树
if(!p->rchild){//右子树空则只需重接它的左子树
q = p;
p = p->lchild;
free(q);
}
else if(!p->lchild){//只需重接它的右子树
q = p;
p = p->rchild;
free(q);
}
else{//左右子树均不空
q = p;
s = p->lchild;
while(s->rchild){//转左,然后向右到尽头
q = s;
s = s->rchild;
}
p->data = s->data;//s指向被删结点的“前驱”
if(q != p)//重接*q的右子树
q->rchild = s->lchild;
else//重接*q的左子树
q->lchild = s->lchild;
delete s;
}
return TRUE;
}