定义

二叉排序树或者非空二叉树,或者为具有以下性质的二叉树:
1、若根结点的左子树不空,则左子树上所有结点的值都小于根结点的值;
2、若根结点的右子树不空,则右子树上所有结点的值都大于或者等于根结点的值;
每一棵子树分别也是二叉排序树

上述定义为递归定义

如下图:

二叉树(四)——二叉排序树_ASL


该二叉树的中序序列如下:

10, 30, 35, 38, 40, 50, 50, 58, 60, 64, 70, 73, 100

我们发现二叉排序树的中序序列从小到大递增

二叉排序树的建立

逐点插入法

设K=( k1,k2,k3, …, kn)为具有n 个数据元素的序列。从序列的第一个元素开始,依次取序列中的元素,每取一个元素ki,按照下述原则将ki 插入到二叉树中:
1、若二叉树为空,则ki 作为该二叉树的根结点;
2、若二叉树非空,则将ki 与该二叉树的根结点的值进行比较;若ki 小于根结点的值,则将ki插入到根结点的左子树中:否则,将ki 插入到根结点的右子树中。
3、将ki 插入到左子树或者右子树中仍然遵循上述原则

建立二叉排序树的(主)算法

建立二叉排序树的(主)算法的C语言实现如下:

BTREE SORTTREE(datatype K[ ], int n)
{
BTREE T=NULL;
int i;
for(i=0; i<n; i++)
INSERTBST(T, K[i]); //调用插入算法
return T;
}

主算法很简单,循环调用每个节点的插入算法。其中,插入一个节点的非递归算法如下:

#define
void INSERTBST(BTREE &T, typedata item)
{
BTREE p, q;
p=(BTREE)malloc(len); //建立一个新结点
p->data=item;
p->lchild=NULL;
p->rchild=NULL;
if(T==NULL)
T=p;
else{
q=T; //q移动,进行查找
while(1)
if(item<q->data)
if(q->lchild==NULL){
q->lchild=p; //插入结点
break;
}else
q=q->lchild;
else
if(q->rchild==NULL){
q->rchild=p; //插入结点
break;
}else
q=q->rchild;
}
}

二叉排序树的删除

二叉排序树的删除原则如下:
1、被删除结点为叶结点,则直接删除;
2、被删除结点无左子树,则用右子树的根结点取代被删除结点;
3、被删除结点无右子树,则用左子树的根结点取代被删除结点;
4、被删除结点的左、右子树都存在,则用被删除结点的右子树中值最小的结点(或被删除结点的左子树中值最大的结点)取代被删除结点。

二叉排序树的查找

二叉排序树的查找过程

二叉排序树的查找过程如下:
若二叉排序树为空,则查找失败,结束。
若二叉排序树非空,则将被查找元素与二叉排序树的根结点的值进行比较,
1、若等于根结点的值,则查找成功,返回被查到元素所在链结点的地址,查找结束;
2、若小于根结点的值,则到根结点的左子树中重复上述查找过程;
3、若大于根结点的值,则到根结点的右子树中重复上述查找过程;
直到查找成功或者失败。

该过程是一个递归过程;由于查找过程和插入过程很相像,所以二叉排序树也叫二叉查找树。

同时做如下约定
1、若查找成功,给出被查找元素所在结点的地址;
2、若查找失败,给出信息NULL;
3、二叉树采用二叉链表存储结构。

查找算法

二叉排序树的查找算法如上所述,该算法可以使用递归实现,也可以不使用。

递归实现查找算法

BTREE SORTSEARCH2( BTREE T, datatype key )
{
if(T!=NULL){
if(T->data==key)
return T; // 查找成功
if(T->data<key) // 查找T的右子树
return SORTSEARCH2(T->rchild, key);
else // 查找T的左子树
return SORTSEARCH2(T->lchild, key);
} else
return NULL; // 查找失败
}

递归算法易于理解,但是效率较低。

非递归实现查找算法

BTREE SORTSEARCH1(BTREE T,datatype key)
{
BTREE p=T;
while(p!=NULL){
if(p->data==key)
return p; //查找成功
if(p->data<key)
p=p->rchild; //将p移到右子树的根结点
else
p=p->lchild; //将p移到左子树的根结点
}
return NULL; //查找失败
}

非递归算法不易于理解,但是效率较高。

查找效率

二叉排序树的查找效率可以用平均查找长度ASL来评估

ASL定义如下:

平均查找长度ASL —— 确定一个元素在树中位置所需要进行的元素间的比较次数的期望值(平均值),计算公式如下:

二叉树(四)——二叉排序树_ASL_02


其中:

1、n表示二叉树中结点的总数;

2、pi表示查找第i个元素的概率;

3、ci表示查找第i个元素需要进行的元素之间的比较次数。以如下二叉排序树为例,其ASL计算过程如下:

二叉树(四)——二叉排序树_二叉排序树_03

ASL的计算方法如下:
第一层元素个数 *1 + 第二层元素个数 *2 + 第三层元素个数 *3+……+第n层元素个数 *n 。
可以利用二叉树的按层遍历,然而将每层的元素个数乘以第几层。

注:
如果被插入的元素序列是随机序列,或者序列的长度较小,采用逐点插入法建立二叉排序树可以接受。如果建立的二叉排序树中出现结点子树的深度之差较大时(即产生不平衡),就有必要采用其他方法建立二叉排序树,即建立所谓“平衡二叉树”。

比较理想的情况下,二叉排序树查找的时间复杂度为O(log2n),当出现“退化二叉树”时,时间复杂度为O(n)