二叉排序树又称为二叉查找树
递归定义:二叉排序树可以是空树,或具有如下性质:
1、若它的左子树非空,则左子树上所有的结点的值均小于根节点的值;
2、若它的右子树非空,则右子树上所有结点的值均大于或者等于根结点的值。
3、它的左右子树也分别为二叉排序/查找树
二叉排序树的存储结点为二叉树,使用二叉链表作为存储结构
!!二叉排序树的插入与创建
(1)二叉排序树的插入
算法思想:
1>.若二叉树是空树,则key成为二叉排序树的根。
2>.若二叉排序树非空,则将key与二叉排序树的跟进行比较:
如果key的值等于根节点的值,则停止插入
如果key的值小于根结点的值,则将key插入左子树
如果key的值大于根结点的值,则将key插入到右子树
二叉排序树的定义
typedef struct node{
int key;//关键字的值
struct node *lchild,*rchild;
}BSTNode,*BSTree;
二叉排序树插入的递归算法
void InsertBST(BSTree *bst,int key){
BSTree s;
if(*bst==NULL){//递归结束条件,空树,将key作为它的根
s=(BSTree)malloc(sizeof(BSTNode)); //申请新的节点
s->key=key;
s->lchild=NULL;
s->rchild=NULL;
*bst=s;
}
else if(key<(*bst)->key)){ //将s插入到左子树
InsertBST(&((*bst)->lchild),key);
}
else if(key>(*bst)->key)
InsertBST(&((*bst)-rchild),key);
}
二叉排序树的插入算法的时间复杂度为O(log2n)。
(2)二叉排序树的创建
算法思想:
先将二叉排序树初始化为一棵空树,然后逐个读入元素,每读一个元素创立一个新的结点,并插入到当前已经生成的二叉排序树中,即通过多次调用插入新节点的算法实现。注意:插入时比较结点顺序始终是从二叉树的根结点开始。
创建二叉排序树
void createBST(BSTree *bst){//从键盘输入元素的值,创建相应的二叉排序树
int key;
*bst=NULL;
scanf("%d",&key);
while(key!=ENDKEY){
InsetBST(bst,key);
scanf("%d",&key);
}
}
假设有n个元素则需要插入n次,创建二叉排序树的时间复杂度为O(nlog2n)。
《3》二叉排序树的查找
因为二叉排序树可以看作是一个有序表,所以在二叉排序树上进行查找和折半查找类似
算法思想:
首先将待查关键字key与根结点关键字t进行比较,若:
1、key=t,则返回根结点地址
2、key<t,则进一步查找左子树
3、key>t,则进一步查找右子树
递归算法:
BSTree searchBST(BSTree bst,int key){
//在指针bst所指二叉排序树中,递归查找某关键字等于key的元素,若查找成功,返回指向该元素结点指针,否则返回空指针
if(bst) return NULL;
else if(bst->key==key) return bst;
else if(bst->key>key) return searchBST(bst->lchild,key);//在左子树继续查找
else return searchBST(bst->rchild,key);
}
非递归算法:
BSTree searchBST(BSTree bst,int key){
//在指针bst所指二叉排序树上查找关键字key的结点,若查找成功,返回指向该元素结点指针,否则返回空指针
BSTree q;
q=bst;
while(q){
if(q->key==key) return q;
if(q->key>key) q=q->lchild;
else q=q->rchild;
}
return NULL;//查找失败
}
对于需要经常做插入、删除、查找运算的表,宜采用二叉排序树结构。
《4》二叉排序树的删除
从二叉排序树上删除一个结点,不能把以该结点为根的子树都删去,并且还需要保证删除后仍然保持二叉排序树的性质不变。所以说,在二叉排序树中删除一个结点相当于删去有序序列中的一个结点。
算法思想:
删除操作首先应该查找到该结点,看能否查找到,如果可以找到,假设要删除的结点为P,结点P的双亲结点为F,并假设结点P是结点F的左孩子(或者右孩子),则有:
1>.若p为叶子结点,则可以直接删去。f->lchild=NULL;free(p);
2>.若p结点只有左子树或者右子树,则可将p的左子树或者右子树,直接改为其双亲结点f的左子树。f->lchild=p->lchild;(或者f->lchild=p->rchild);free(p);
3>.若p既有左子树又有右子树,则有两种方法:
方法一:首先找到p结点在中序序列中的直接前驱s结点,然后将p的左子树改为f的左子树,将p的右子树改为s的右子树
方法二:首先找到p结点在中序序列中的直接前驱s结点,然后用s结点的值替代p结点的值,再将s节点删除,原s结点的左子树改为s的双亲结点q的右子树
BSTNode *DelBST(BSTree t,int key){
BSTNode *p,*f,*s,*q;
p=t;f=NULL;
while(p){ //查找p结点过程
if(p->key==key) break;
f=p;
if(p->key>k) p=p->lchild;
else p=p->rchild;
}
if(p=NULL) return t;//查找不到,返回原来的二叉排序树
if(p->lchild==NULL){//当p没有左子树的时候
if(f==NULL) t=p->rchild; //p是原二叉排序树的根
else if(f->lchild==p) //p是f的左孩子
f->lchild=p->rchild;
else //p是f的右孩子
f->rchild=p->rchild;
free(p);
}
else {//p有右子树
q=p;
s=p->lchild;
while(s->rchild){ //在p的左子树中查找最右下结点
q=s;
s=s->rchild;
}
if(q==p)
q->lchild=s->child;//将s的左子树链到q上
else
q->rchild=s->lchild;
p->key=s->key;
free(s);
}
return t;
}