一、二叉排序树概念
二叉排序树又称为二叉查找树。它或者是空树,或者是满足如下性质的二叉树:
(1)若它的左子树非空,则左子树上所有结点的值均小于根结点的值。
(2)若它的右子树非空,则右子树上所有结点的值均大于根结点的值。
(3)它的左、右子树本身又各是一棵二叉排序树。
二、二叉排序树算法思想
1、插入基本思想
若二叉排序树为空,将待插入的结点作为根结点。否则,若待插入结点的关键字值和根结点关键字值进行比较。若小于,则作为根结点左子树插入,否则作为右子树插入。
按中序遍历该二叉树所得到的序列是一个递增有序序列。二叉排序树是用非线性结构表示有序线性表的一种方法。
2、二叉排序树的查找基本思想
(1)当二叉树为空树时,检索失败。
(2)如果二叉排序树根结点的关键字等于待检索的关键字,则检索成功。
(3)如果二叉排序树根结点的关键字小于待检索的关键字,则在根结点的右子树中用相同的方法继续检索。
(4)如果二叉排序树根结点的关键字大于待检索的关键字,则在根结点的左子树中用相同的方法继续检索。
3、二叉排序树的删除基本思想
(1)若待删除的结点是叶结点,直接删去该结点。
(2)若待删除的结点只有左子树而无右子树。根据二叉排序树的特点,可以直接将其左子树的根结点放在被删结点的位置。
(3)若待删除的结点只有右子树而无左子树。与(2)情况类似,可以直接将其右子树的根结点放在被删结点的位置。
(4)若待删除的结点同时有左子树和右子树。根据二叉排序树的特点,可以从其左子树中选择关键字最大的结点(直接前驱结点)或右子树中选择关键字最小的结点(直接后继结点)放在(覆盖)被删去结点的位置上。假如选取右子树上关键字最小的结点,那么该结点一定是右子树的最左结点。假如选取左子树上关键字最大的结点,那么该结点一定是左子树的最右结点。
三、二叉排序数的操作及C语言描述
1、插入
2、查找
3、删除
四、二叉排序数的C语言实现
#include"stdio.h"
#include"stdlib.h"
#include"string.h"
#include"math.h"
#define OK 1
typedef intKeyType;
typedef int info;
typedef struct
{
KeyType key;
//info otherinfo;
}ElemType;
typedef structBiTNode
{
ElemType data;
BiTNode *lchild,*rchild; // 左右孩子指针
}BiTNode,*BiTree;
intSearchBST(BiTree T,KeyType key,BiTree f,BiTree &p)
{
if(!T) {p=f;return0;}
elseif(key==T->data.key) {p=T;return 1;}
elseif(key<T->data.key) SearchBST(T->lchild,key,T,p);
else SearchBST(T->rchild,key,T,p);
}//SearchBST
intInsertBST(BiTree &T,ElemType e)
{
BiTree s,p;
if(!SearchBST(T,e.key,NULL,p))
{
s=(BiTree)malloc(sizeof(BiTNode));
s->data=e;
s->lchild=s->rchild=NULL;
if(!p) T=s;
else if(e.key<p->data.key)p->lchild=s;
else p->rchild=s;
return 1;
}
else return 0;
}//InsertBST
int Delete(BiTree&p)
{
BiTree q,s;
if(!p->rchild)
{
q=p;
p=p->lchild;
free(q);
}//if
elseif(!p->lchild)
{
q=p;
p=p->rchild;
free(q);
}//else if
else
{
q=p;
s=p->lchild;
while(s->rchild) {q=s;s=s->rchild;}
p->data=s->data;
if(q!=p) q->rchild=s->lchild;
else q->lchild=s->lchild;
delete s;
}//else
return 1;
}//Delete
intDeleteBST(BiTree &T,KeyType key)
{
if(!T) return 0;
else
{
if(key==T->data.key) return Delete(T);
else if(key<T->data.key) returnDeleteBST(T->lchild,key);
else return DeleteBST(T->rchild,key);
}//else
}//DeleteBST
intInsertBSTD(BiTree &T)
{
ElemType e;
printf("insertthe data,until input -1:\n");
scanf("%d",&e.key);
while(e.key!=-1)
{
InsertBST(T,e);
scanf("%d",&e.key);
}//while
return 1;
}//InsertBSTD
void PrintD(BiTreeT)
{
if(T->lchild)PrintD(T->lchild);
printf("->%d",T->data.key);
if(T->rchild)PrintD(T->rchild);
}//PrintD
intDeleteBSTD(BiTree &T)
{
ElemType e;
printf("\ninputthe data you want to delete:\n");
scanf("%d",&e.key);
DeleteBST(T,e.key);
return 1;
}//DeleteBSTD
int main()
{
BiTree T;
InsertBSTD(T);
PrintD(T);
DeleteBSTD(T);
PrintD(T);
return OK;
}
五、复杂度分析
在二叉排序树上查找其关键字等于给定值的结点的过程,恰是走了一条从根结点到该结点的路径的过程。和给定值比较的关键字次数等于路径长度加1(或结点所在层次数)。因而,和折半查找类似,与给定值比较的关键字个数不超过树的深度。然而,折半查找长度为n的表的判定树是惟一的,而含有n个结点的二叉排序树并不唯一,其平均查找长度和树的形态有关。如图所示:
其同样的数据,输入的顺序不同,其树的形态就不一样,导致平均查找长度也不一样。当表中记录按关键字有序时,构成的二叉排序树蜕变为歪斜树。树的深度为n,其平均查找长度为(n+1)/2(和顺序查找相同),这是最差的情况。显然,最好情况下平均查找长度和log2n成正比。那么平均性能如何呢?在随机输入数据的情况下,其平均查找长度是多少呢?
可见,在随机的情况下,二叉排序树的平均查找长度和logn是等数量级的。
为了避免出现歪斜树,在构造二叉排序树的过程中需要不断进行平衡处理,使其成为平衡二叉树。