动态查找表:表结构本身是在查找过程中动态生成的,即对于给定值key,若表中存在其关键值等于key的记录,则查找成功返回,否则插入关键字等于key的记录。
二叉排序树或者是一颗空树,或者是具有下列性质的二叉树:
1、若他的左子树不为空,则左子树上所有结点的值均小于它的根结点的值。
2、若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3、它的左右子树也分别为二叉排序树。
二叉排序树又称二叉查找树,根据上述定义的结构特点可见,它的查找过程与次优二叉树类似,即当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将根据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。通常,可取二叉链表作为二叉排序树的存储结构。
首先是辅助宏的定义:
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define NULL 0
#define LH 1 //左高
#define EH 0 //等高
#define RH -1 //右高
typedef int Status;
typedef int KeyType;
typedef char* InfoType;
二叉排序树的存储结构定义:
//二叉排序树的存储结构定义
typedef struct{
KeyType key;
InfoType otherinfo; //附加信息
}ElemType;
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
typedef BiTNode BSTNode;
typedef BiTree BSTree;
查找(递归实现):
算法思想:
若为空,返回NULL。
不空时,
若查找的关键字等于跟结点,返回T;
否则
若小于根,查其左子树,返回查找结果;
若大于根,查其右子树,返回查找结果;
BSTree SearchBST(BSTree T,KeyType key){
/*查找(递归实现)
若为空 返回NULL 不空时,若查找的关键字等于根结点
返回T 否则若小于根 查其左子树 返回查找结果 若大
于根 查其右子树 返回查找结果*/
if(!T)
return NULL;
else if(T->data.key==key) //在左子树继续查找
return T;
else if(T->data.key<key) //在右子树继续查找
return SearchBST(T->rchild,key);
else
return SearchBST(T->lchild,key);
}
查找(非递归实现):
p最初指向根结点,只要p不空且p所指结点不是所求则根据比较结果令p变为当前结点的左孩子或右孩子。
如此重复直到p空或者找到。
BSTNode *Search(BSTree T,KeyType key){
/*查找(非递归实现)
p指向根结点 只要p不空且p所指结点不是所求则根据比较
结果令 p变为 当前结点的左孩子 或右孩子。如此重复则
最终p空或者找到*/
BSTNode *p=T;
while(p!=NULL&&p->data.key!=key){
if(key<p->data.key)
p=p->lchild;
else
p=p->rchild;
}
return p;
}
判断一颗给定二叉树是否是二叉排序树。
运用递归的思想,空树是二叉排序树;当树不空时,先判断左右子树是否是二叉排序树,只要有一个不是则原树不是二叉排序树,如果左右子树都是二叉排序树,看看左子树中最大的是否比根结点小,右子树中最小的是否比根结点大即可。
Status IsBST(BSTree &T)
{
//判断T是否为二叉排序树
BSTNode *p;
if(!T)
return TRUE;
else
{
if(!IsBST(T->lchild))
return FALSE;
if(!IsBST(T->rchild))
return FALSE;
if(T->lchild)
{
//找左子树中最大的与根进行比较
p=T->lchild;
while(p&&p->rchild)
p=p->rchild;
if(p->data.key>T->data.key)
return FALSE;
}
if(T->rchild)
{
//找右子树中最大的与根进行比较
p=T->rchild;
while(p&&p->lchild)
p=p->lchild;
if(p->data.key<T->data.key)
return FALSE;
}
return TRUE;
}
}
二叉排序树的插入.
若二叉排序树为空,则插入结点应为根结点。
否则,在已有二叉排序树中查找是否存在相等结点。
若树中已有,不再插入。
若树中没有,则查找过程中必然会落空,该落空的位置就是新结点应该在的位置。
插入的过程与查找基本类似。新插入的结点一定在叶结点上。
Status InsertBST(BSTree &T,KeyType key)
{
/*二叉排序树的插入
若二叉排序树为空 则插入结点为根结点
否则 在已有二叉排序树中查找是否存在相等结点
若树中已有 不在插入
若树中没有 则查找过程中必然会落空 该落空的位
置就是新结点应该在的位置*/
if(!T)
{
BSTNode *s;
if(!(s=(BSTNode *)malloc(sizeof(BSTNode))))
exit(OVERFLOW);
s->data.key=key;
s->lchild=s->rchild=NULL;
T=s;
return OK;
}
else if(key==T->data.key)
return ERROR;
else if(key<T->data.key)
return InsertBST(T->lchild,key);
else
return InsertBST(T->rchild,key);
}
二叉排序树的创建:
从空树出发,依次按照结点插入方法插入各结点。
Status CreateBST(BSTree &T)
{
//二叉排序树的创建
//从空树出发,依次按照结点插入方法插入各结点即可
T=NULL;
KeyType key;
scanf("%d",&key);
while(key)
{
if(InsertBST(T,key))
scanf("%d",&key);
else
return ERROR;
}
return OK;
}
二叉排序树的删除:
首先定位被删除的结点及其双亲,如果不存在关键字等于key的结点,则直接返回。
否则,根据被删结点特性分类处理,保证删除后仍是二叉排序树。
1、被删除的结点是叶子结点。若有双亲则将双亲结点中相应指针域的值置空,否则T置空。
2、被删结点只有左子树或右子树。双亲结点相应指针指向被删结点的唯一子树。
3、被删结点既有左子树也有右子树。找左子树最大的元素代替被删除元素,归结为前一情况。
void DeleteBFT(BSTree &T,KeyType key)
{
/*二叉排序树的删除
首先定位被删除的结点及其双亲
如果不存在关键字等于key的结点则直接返回
否则 根据被删除结点特性分类处理 保证删后
仍是二叉排序树
被删除的是叶子结点 若有双亲 则将双亲结点中相
应指针域的值置空 否则T置空
被删的结点只有左子树或右子树 双亲结点相应指针
域指向被删结点的唯一子树
被删结点既有左子树也有右子树 找左子树中最大的
代替删除元素
*/
BSTNode *p=T,*f=NULL,*q;
while(p&&p->data.key!=key)
{
if(key<p->data.key)
{
f=p;
p=p->lchild;
}
else
{
f=p;
p=p->rchild;
}
}
if(!p)
return;
if(!p->lchild&&!p->rchild)
{
if(!f)
{
free(p);
T=NULL;
p=NULL;
}
else if(f->lchild==p)
f->lchild=NULL;
else
f->rchild=NULL;
free(p);
p=NULL;
}
else if(!p->lchild)
{
if(!f)
T=p->rchild;
else if(f->lchild==p)
f->lchild=p->rchild;
else
f->rchild=p->rchild;
free(p);
p=NULL;
}
else if(!p->rchild)
{
if(!f)
T=p->lchild;
else if(f->lchild==p)
f->lchild=p->lchild;
else
f->rchild=p->lchild;
free(p);
p=NULL;
}
else
{
f=p; //f始终指向q的双亲 方便后面的删除
q=p->lchild;
while(q->rchild) //q定位最大 f指向其双亲
{
f=q;
q=q->rchild;
}
p->data.key=q->data.key; //左子树最大者的值填充到原本被删结点
if(f->lchild==q) //删除左子树中最大者
f->lchild=q->lchild;
else
f->rchild=q->lchild;
free(q);
q=NULL;
}
}
二叉排序树查找的性能分析:
平均查找长度和二叉树的形态有关,即,
最好 logN。形态均匀,与二分查找的判定树相似。
最坏:(n+1)/2