标题：二叉排序树
查找
步骤：若根结点的关键字值等于查找的关键字，成功。
否则，若小于根结点的关键字值，递归查左子树。
若大于根结点的关键字值，递归查右子树。
若子树为空，查找不成功。
平均情况分析（在成功查找两种的情况下）
在一般情况下，设 P（n，i）且它的左子树的结点个数为 i 时的平均查找长度。如图的结点个数为 n = 6 且 i = 3; 则 P（n,i）= P（6, 3） = [ 1+ ( P(3) + 1) * 3 + ( P(2) + 1) * 2 ] / 6
= [ 1+ ( 5/3 + 1) * 3 + ( 3/2 + 1) * 2 ] / 6
注意：这里 P(3)、P(2) 是具有 3 个结点、2 个结点的二叉分类树的平均查找长度。 在一般情况，P（i）为具有 i 个结点二叉分类树的平均查找长度。 P(3) = （1+2+2）/ 3 = 5/3
P(2) = （1+2）/ 2 = 3/2
∴ P（n,i）= [ 1+ ( P(i) + 1) * i + ( P(n-i-1) + 1) * (n-i-1) ] / n 
n  -1
∴ P（n）= ∑ P（n,i）/ n <= 2(1+I/n)lnn
i=0
因为 2(1+I/n)lnn≈1.38logn 故P(n)=O(logn)
插入删除
与次优二叉树相对，二叉排序树是一种动态树表。其特点是：树的结构通常不是一次生成的，而是在查找过程中，当树中不存在关键字等于给定值的节点时再进行插入。新插入的结点一定是一个新添加的叶子节点，并且是查找不成功时查找路径上访问的最后一个结点的左孩子或右孩子结点。
插入算法
首先执行查找算法，找出被插结点的父亲结点。
判断被插结点是其父亲结点的左、右儿子。将被插结点作为叶子结点插入。
若二叉树为空。则首先单独生成根结点。
注意：新插入的结点总是叶子结点。
//在二叉排序树中插入查找关键字key
void InsertBST(t，key)
{
if(t==NULL)
{
t=new BiTree; 
t->lchild=t->rchild=NULL;
t->data=key;
return; 
}
if(key<t->data ) 
InsertBST(t->lchild,key);
else
InsertBST (t->rchild, key ); 
}
//n个数据在数组d中，tree为二叉排序树根
void CreateBiTree(tree,d[ ],n）
{
tree=NULL;
for(i=0;i<n;i++)
InsertBST(tree,d);
}
最小值二叉树c例程：
#include<stdio.h>
struct priorityqueue
{
int capacity;
int size;
struct priorityqueue *elements;
}*tryit;
struct priorityqueue *initialize ( int maxelements )
{
struct priorityqueue *h;
h = malloc ( sizeof ( struct priorityqueue ) );
h -> elements = malloc ( sizeof ( int ) * ( maxelements + 1 ) );
h -> capacity = maxelements;
h -> size = 0;
h -> elements[0] = -23767;
return h;
}
void insert ( int x , struct priorityqueue *h )
{
int i;
for ( i = ++h -> size ; h -> elements[ i / 2 ] > x ; i /= 2 )
h -> elements[ i ] = h -> elements[ i / 2 ];
h -> elements [ i ] = x;
}
int deletemin ( struct priorityqueue *h )
{
int i , child ;
int minelement , lastelement;
minelement = h -> elements[ 1 ];
lastelement = h -> elements[ h -> size-- ];
for ( i = 1 ; i * 2 <= h -> size ; i = child )
{
child = i * 2;
if ( child != h -> size && h -> elements[ child + 1 ] < h -> elements[ child ] )
child++;
if ( lastelement > h -> elements[ child ] )
h -> elements[ i ] = h -> elements[ child ];
else
break;
}
h -> elements[ i ] = lastelement;
return minelement;
}
main()
{
tryit = initialize ( 10 );
insert ( 4 , tryit );
insert ( 5 , tryit );
insert ( 10 , tryit );
insert ( 3 , tryit );
printf ( "%d\n" , deletemin ( tryit ) );
printf ( "%d\n" , deletemin ( tryit ) );
printf ( "%d\n" , deletemin ( tryit ) );
printf ( "%d\n" , deletemin ( tryit ) );
getch();
}
删除结点
在二叉排序树删去一个结点，分三种情况讨论：
若*p结点为叶子结点，即PL(左子树)和PR(右子树)均为空树。由于删去叶子结点不破坏整棵树的结构，则只需修改其双亲结点的指针即可。若*p结点只有左子树PL或右子树PR，此时只要令PL或PR直接成为其双亲结点*f的左子树（当*p是左子树）或右子树（当*p是右子树）即可，作此修改也不破坏二叉排序树的特性。若*p结点的左子树和右子树均不空。在删去*p之后，为保持其它元素之间的相对位置不变，可按中序遍历保持有序进行调整，可以有两种做法：其一是令*p的左子树的最右下节点代替*p，并删除*p的最右下节点；其二是令*p的直接前驱（或直接后继）替代*p，然后再从二叉排序树中删去它的直接前驱（或直接后继）。
C++代码
Status DeleteBST(BiTree &T, KeyType key){
//若二叉排序树T中存在关键字等于key的数据元素时，则删除该数据元素，并返回
//TRUE；否则返回FALSE
if(!T)
return false; //不存在关键字等于key的数据元素
else{
if(key == T->data.key) { // 找到关键字等于key的数据元素
return Delete(T);
}
else if(key < T->data.key)
return DeleteBST(T->lchild, key);
else
return DeleteBST(T->rchild, key);
}
}
Status Delete(BiTree &p){
//从二叉排序树中删除结点p，并重接它的左或右子树
if(!p->rchild){ //右子树空则只需重接它的左子树
q=p;
p=p->lchild;
delete q;
}
else if(!p->lchild){ //左子树空只需重接它的右子树
q=p;
p=p->rchild;
delete q;
}
else{ //左右子树均不空
q=p;
s=p->lchild;
while(s->rchild){
q=s;
s=s->rchild;
} //转左，然后向右到尽头
p->data = s->data; //s指向被删结点的“前驱”
if(q!=p)
q->rchild = s->lchild; //重接*q的右子树
else
q->lchild = s->lchild; //重接*q的左子树
delete s;
}
return true;
}[1]
性能分析
  每个结点的C(i)为该结点的层次数。最坏情况下，当先后插入的关键字有序时，构成的二叉排序树蜕变为单支树，树的深度为，其平均查找长度为(n+1)/2(和顺序查找相同），最好的情况是二叉排序树的形态和折半查找的判定树相同，其平均查找长度和log 2 (n)成正比
优化
Size Balanced Tree(SBT) 
AVL树
红黑树
Treap(Tree+Heap) 
这些均可以使查找树的高度为O(log(n))